(1) 主要问题:在fork之前的printf函数,若有”\n”,如printf(“Hello World!\n”),则会输出两次,否则如printf(“Hello World!”),则只输出一次?
解决方式:使用fork函数创建一个子进程,子进程是父进程的一个“复制品”,父子进程为独立进程,平等调度,用户空间独立 。也就是说,子进程的数据、代码等资源与父进程是一样的,这就意味着子进程也有printf函数的代码。”\n”实际上不只是回车换行功能,它同时清空了缓冲区,这样子进程内存中就没有这个字符串;而如果没有”\n”,则字符串还留在缓冲区中,子进程复制了父进程的内存,所以会有这个字符串输出。
(2) 主要问题:如何判断子进程被父进程成功杀死?
解决方式:老师给的kill函数的参考颇令人费解,因此查找到正确的如下:
kill(传送信号给指定的进程,使用 kill -l 命令可查看linux系统 中信号。)
相关函数: raise,signal
表头文件 :#include<sys/types.h> #include<signal.h>
定义函数 :int kill(pid_t pid,int sig);
函数说明 :
kill()可以用来送参数sig指定的信号给参数pid指定的进程。
参数pid 有几种情况:
<!--[if !supportLists]-->1) <!--[endif]-->pid>0 将信号传给进程识别码为pid 的进程。
<!--[if !supportLists]-->2) <!--[endif]-->pid=0 将信号传给和目前进程相同进程组 的所有进程
<!--[if !supportLists]-->3) <!--[endif]-->pid=-1 将信号广播传送给系统内所有的进程
<!--[if !supportLists]-->4) <!--[endif]-->pid<0 将信号传给进程组识别码为pid绝对值 的所有进程
参数sig可以置为SIGINT或SIGTERM。
返回值 执行成功则返回0,如果有错误则返回-1。
因此判断子程序是否成功被父程序杀死的代码可为:
int re= kill(child_pid,SIGINT);
if(re==0)
//success..
else if(re==-1)
//failture…
(3) 主要问题:在子进程运行时,调用waitpid(child_pid,&status,WNOHANG)的结果为0。但是!子进程使用return自杀,调用waitpid(child_pid,&status,WNOHANG)的结果为-1,并不为子进程的ID;而子进程被父进程杀死后,调用waitpid(child_pid,&status,WNOHANG)的结果为0。为什么是这样的结果?
解决方式:查询资料得——对于进程的一生可以用一些形象的比喻作一个小小的总结:
随着一句fork,一个新进程呱呱落地,但它这时只是老进程的一个克隆。然后随着exec,新进程脱胎换骨,离家独立,开始了为人民服务的职业生涯。人有生老病死,进程也一样,它可以是自然死亡,即运行到main函数的最后一个”}”,从容地离我们而去;也可以是自杀,自杀有2种方式,一种是调用 exit函数,一种是在main函数内使用return,无论哪一种方式,它都可以留下遗书,放在返回值里保留下来;它还甚至能可被谋杀,被其它进程通过另外一些方式结束他的生命。进程死掉以后,会留下一具僵尸,wait和waitpid充当了殓尸工,把僵尸推去火化,使其最终归于无形。
waitpid
相关函数:wait
表头文件:#include<sys/types.h> #include<sys/wait.h>
定义函数:pid_t waitpid(pid_t pid,int * status,int options);
函数说明:
waitpid()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用 waitpid()时子进程已经结束,则 waitpid()会立即返回子进程结束状态值。
参数status 子进程的结束状态值会由其返回, 而子进程的进程识别码也会一起返回。如果不在意结束状态值,则 参数 status 可以设成 NULL。
参数pid 为欲等待的子进程识别码,其他数值意义如下:
<!--[if !supportLists]-->1) <!--[endif]-->pid<-1 等待进程组 识别码为 pid 绝对值 的任何子进程;
<!--[if !supportLists]-->2) <!--[endif]-->pid=-1 等待任何子进程,相当于 wait();
<!--[if !supportLists]-->3) <!--[endif]-->pid=0 等待进程组识别码与目前进程相同的任何子进程;
<!--[if !supportLists]-->4) <!--[endif]-->pid>0 等待任何子进程识别码为 pid 的子进程。
参数options 提供了一些额外的选项来控制waitpid:
<!--[if !supportLists]-->1) <!--[endif]-->为WNOHANG, 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待,若结束,则返回该子进程的ID;
<!--[if !supportLists]-->2) <!--[endif]-->为WUNTRACED, 若子进程进入暂停状态,则马上返回,但子进程的结束状态不予以理会;
<!--[if !supportLists]-->3) <!--[endif]-->为0,则不使用任何选项。
返回值
<!--[if !supportLists]-->1) <!--[endif]-->当正常返回的时候,waitpid返回收集到的子进程的进程ID;
<!--[if !supportLists]-->2) <!--[endif]-->如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
<!--[if !supportLists]-->3) <!--[endif]-->如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
如此发现,是自己的理解有问题。根据资料以及多次试验猜想:子进程无论是自然死亡,还是自杀或是被父进程杀死,都可在一段时间后用waitpid返回收集到该子进程的pid。而该进程一旦被waitpid收集完以后,如果再用waitpid收集,则会报错!
另外,我还发现两个问题:一是如果子进程被父进程杀死后不能马上用waitpid收集,依然返回0;二是父进程杀死子进程后用waitpid返回的是2。
例子1:
#include<sys/types.h> #include<sys/wait.h> #include<unistd.h> #include<stdio.h> int main() { pid_t pc,pr; int status; pc=fork(); if (pc<0)/* fork错误*/ { printf("fork error\n"); exit(1); } else if(pc==0)/*在子进程中*/ { printf("child pid=%d\n",getpid()); sleep(5); exit(0); } else { printf("parent pid=%d\n",getpid()); int c=0; do {/* 使用了WNOHANG参数,waitpid不会在这里等待 */ pr=waitpid(pc,&status,WNOHANG); if (pr==0) { c++; if(c==3) kill(pc,SIGINT); //父进程杀死子进程。注释掉此句为子进程自杀。 printf("No child exit, so waitpid return 0!\n"); sleep(1); } }while (pr==0); if (pr==pc) printf("waitpid successfully get child %d, and status is %d\n",pr,status); else printf("wait child error\n"); printf("error: %d\n",waitpid(pc,&status,WNOHANG)); //出错:输出-1 } return 0; }
例子2:
#include <unistd.h> #include <sys/types.h> #include <signal.h> #include <stdio.h> #include <sys/wait.h> int main(int argc,char* argv[]) { pid_t child1_pid,child2_pid; int p1,p2; int count=0; /*fork*/ child1_pid = fork(); //子进程1 if(child1_pid < 0) { puts("fork fail!"); return -1; } else if(child1_pid == 0) { // puts("子进程1正在执行……"); while(1); return 0; } else { child2_pid=fork(); //子进程2 if(child2_pid<0) { puts("fork fail!"); return -1; } else if(child2_pid==0) { // puts("子进程2正在执行……"); while(1); return 0; } puts("父进程正在执行……"); do{ if(count==4) { if(kill(child1_pid,SIGINT)==0) puts("子进程1被父进程杀死"); if(kill(child2_pid,SIGINT)==0) puts("子进程2被父进程杀死"); }/*从杀死子进程到收集子进程还是有一段时间的!*/ p1=waitpid(child1_pid,NULL,WNOHANG); p2=waitpid(child2_pid,NULL,WNOHANG); if(p1==0){ puts("子进程1正在执行……"); sleep(1); count++;} if(p2==0){ puts("子进程2正在执行……"); sleep(1); count++;} }while(p1==0||p2==0); /*kill*/ if(p1==child1_pid) printf("父进程取得被杀死的子进程1的pid %d\n",p1); if(p2==child2_pid) printf("父进程取得被杀死的子进程2的pid %d\n",p2); puts("父进程结束"); } return 0; }
一些参考网址:
1.http://www.chinaunix.net/old_jh/23/907131.html
2.http://topic.csdn.net/u/20080730/12/52c12489-55f2-49a1-891d-76e882921856.html
4.http://baike.baidu.com/view/22085.htm#4
5.http://baike.baidu.com/view/2365304.htm
6.http://doc.linuxpk.com/53457.html