LIinux下C语言进程管理

 

(1) 主要问题:fork之前的printf函数,若有”\n”,如printf(“Hello World!\n”),则会输出两次,否则如printf(“Hello World!”),则只输出一次?

解决方式:使用fork函数创建一个子进程,子进程是父进程的一个复制品,父子进程为独立进程,平等调度,用户空间独立 。也就是说,子进程的数据、代码等资源与父进程是一样的,这就意味着子进程也有printf函数的代码。”\n”实际上不只是回车换行功能,它同时清空了缓冲区,这样子进程内存中就没有这个字符串;而如果没有”\n”,则字符串还留在缓冲区中,子进程复制了父进程的内存,所以会有这个字符串输出。

 

(2) 主要问题:如何判断子进程被父进程成功杀死?

解决方式:老师给的kill函数的参考颇令人费解,因此查找到正确的如下:

kill(传送信号给指定的进程,使用 kill -l 命令可查看linux系统 中信号。)

相关函数: raisesignal

表头文件 #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可以置为SIGINTSIGTERM

返回值 执行成功则返回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,无论哪一种方式,它都可以留下遗书,放在返回值里保留下来;它还甚至能可被谋杀,被其它进程通过另外一些方式结束他的生命。进程死掉以后,会留下一具僵尸,waitwaitpid充当了殓尸工,把僵尸推去火化,使其最终归于无形。

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

3.http://zhidao.baidu.com/question/371085775.html&__bd_tkn__=64f55a272c649b2d573da233b4a123b1830dd5fb8078338d51fed8133ea5c69d362ad36bb4bcda3b39bb3949f6bbe47087ac3af56e60b1f4e7eb60157b5bfc329562aeff5b0f03de01252775a130b80c48059e077b28cf88a649407b005a3328b8127c3149bdadd99506faaccbdc8c0bc93523f74da1

 

4.http://baike.baidu.com/view/22085.htm#4

5.http://baike.baidu.com/view/2365304.htm

6.http://doc.linuxpk.com/53457.html


猜你喜欢

转载自zjh776.iteye.com/blog/1698106