红联Linux门户
Linux帮助

【Linux】利用fork()创建多个线程

发布时间:2016-12-20 10:35:10来源:linux网站作者:yongh701
在《【Linux】fork()》(http://www.linuxdiyf.com/linux/27062.html)只是简单交代了如同利用fork()创建子线程的方法,实际是更应该说将一个程序一分为二的方法。还有很多事情隐藏在其中值得细致思考。由于fork()结构的特殊性,如果要用fork()创建多个线程,并不像pthread_create()那样轻松,而且最关键的一点,是你利用for循环和fork()创建出来的多线程,会不明不白地多出N条线程。这主要是由于对fork()的理解不够所造成的。比如如下代码:
 
#include <stdio.h>  
int main(){   
pid_t pid[2];   
int i;  
for(i=0;i<2;i++){  
if((pid[i]=fork())<0){   
printf("Fork() Error!");   
}   
else if(pid[i]==0){  
printf("This is parent %d,child is %d\n",getppid(),getpid());  
}  
else{  
wait(5);   
}  
}  
return 0;   
}
 
看起来好像没有任何问题,创建2条子线程,就是在原有fork()的基础上,建立一个for而已。
但就是不知道会创建出4条线程。那是因为,问题没有想象中的那样简单,父进程现在标号为i=1的循环中创了一个子进程,然后第二次循环,前边的第一个子线程又创建一个子进程,这时明显系统中有四个进程。如下图所示:
【Linux】利用fork()创建多个线程
 
因此这种创建多个子进程的方式不可取,是否一定需要用pthread_create呢?其实并不是,可以用如下的结构,创建多个子进程,以要创建4个为例:
 
#include <stdio.h>  
#define MAX_THREAD 4//设置子线程数量  
int main(){  
int i,status,pid;  
for(i=0;i<MAX_THREAD;i++){ 
status=fork();  
if (status==0||status ==-1){  
break;  
/*每次循环时, 
如果发现是子进程就直接从创建子进程的循环中跳出来, 
不让你进入循环, 
这样就保证了每次只有父进程来做循环创建子进程的工作 
*/  
}  
if(status==-1){//一般不会这种情况!  
printf("创建的子进程,失败");  
}  
else if(status==0){//每个子进程都会执行的代码  
printf("子线程id=%d,我老爸的id=%d,i=%d\n",getpid(),getppid(),i);  
wait(status,NULL,0);  
}  
else{  
printf("父进程id=%d\n",getpid()); 
while((pid=wait(&status))>0){   
printf("终结id为%d的子线程\n", pid);   
}  
}   
return 0;  
}
 
大家需要自己的子进程做什么,直接在else if(status==0){}这个结构里面改就行了。
 
同时,注意到这里停止子进程与《【Linux】fork()》(http://www.linuxdiyf.com/linux/27062.html)停止单个子进程是不通。父进程一般不做任何事情,相当于pthread_create里面的主函数,具体见《【Linux】线程》(http://www.linuxdiyf.com/linux/27065.html),他唯一的职责就是让等待每一个子线程停止。
 
运行结果如下图:
【Linux】利用fork()创建多个线程
 
大家注意到这个运行结果很有意思,i是从3到0倒着来输出的。本身程序就很有意思,if-else if-else这个结构就游离在for循环之外,却如同将这段代码做了4次。
这是因为fork()保存现场,将线程压入栈的特性。i=0时候这个现场被创建的子线程最先入栈,所以他是最后输出的。
if-else if-else这个结构相当于将线程栈里面的线程经过else if中的处理之后一一出栈。
else if中最初能操作的东西,是子线程入栈时候的状态。
 
大家明白了吗,其实这跟汇编语言里面的循环其实很类似的。
 
本文永久更新地址:http://www.linuxdiyf.com/linux/27066.html