Linux下父进程向子进程发送信号

文章介绍了在Linux环境下,如何使用fork创建子进程,通过信号处理函数signal响应软中断,使用kill发送信号给进程,以及如何利用信号集进行信号屏蔽。同时,展示了无名管道和有名管道实现父子进程间通信的方法,确保数据的顺序打印。
摘要由CSDN通过智能技术生成
  • 需要用到的函数:

    kill( )

    int kill(pid,sig)

    int pid,sig;

    其中,pid是一个或一组进程的标识符,参数sig是要发送的软中断信号。

    (1)pid>0时,核心将信号发送给进程pid。

    (2)pid=0时,核心将信号发送给与发送进程同组的所有进程。

    (3)pid=-1时,核心将信号发送给所有用户标识符真正等于发送进程的有效用户标识号的进程。

    signal( )

    signal(sig,function)

    signal(sig,function)

    int sig;

    void (*func) ( )

    sig是一个信号量,而function是一个函数名字,当使用signal接收到信号时,会调用一次参数中的function方法。

    信号集设置与信号屏蔽

    文件头仍然是#include <signal.h>

    声明信号集
    sigset_t sigs;

    清空信号集
    sigemptyset(&sigs);

    添加信号到信号集
    sigaddset(&sigs,SIGINT);

    sigaddset第一个参数为信号集地址,第二个参数为信号名,如SIGINT是Ctrl+c的中断信号,也可以是其他的自定义信号

    屏蔽信号集sigs中的所有信号
    sigprocmask( SIG_BLOCK,&sigs,0);

    这里的SIG_BLOCK代表的功能是将sigs信号集加入到进程屏蔽中,第三个参数0是用来指向信号集的指针。

    SIG_BLOCK //加入信号到进程屏蔽。
    SIG_UNBLOCK //从进程屏蔽里将信号删除。
    SIG_SETMASK //将set的值设定为新的进程屏蔽。

    父进程向子进程发送信号,在按Ctrl+C使父进程退出时子进程屏蔽^c信号,父进程等待子进程运行完后自行退出。

    #include <stdio.h>
    #include <signal.h>
    #include <unistd.h>
    #include <stdlib.h>
    
    void waiting( ),stop( );
    int wait_mark;
    int main( ) {
    	int p1,p2,stdout;
    	while((p1=fork( ))==-1);       /*创建子进程p1*/
    	if (p1>0) {
    		while((p2=fork( ))==-1);     /*创建子进程p2*/
    		if(p2>0) {
    			wait_mark=1;
    			
    			signal(SIGINT,stop);/*接收到^c信号,转stop*/
    			waiting( );
    			kill(p1,16);        /*向p1发软中断信号16*/
    			kill(p2,17);        /*向p2发软中断信号17*/
    			wait(0);           /*同步*/
    			wait(0);
    			printf("Parent process is killed!\n");
    			exit(0);
    		} else {
    			//声明信号集
    			sigset_t sigs;
    			//清空信号集
    			sigemptyset(&sigs);
    			//添加信号到信号集
    			sigaddset(&sigs,SIGINT);
    			//屏蔽SIGINT信号
    			sigprocmask( SIG_BLOCK,&sigs,0);
    
    			wait_mark=1;
    			signal(17,stop);   /*接收到软中断信号17,转stop*/
    			waiting( );
    			lockf(stdout,1,0);
    			printf("Child process 2 is killed by parent!\n");
    			lockf(stdout,0,0);
    			exit(0);
    		}
    	} else {
    		//声明信号集
    		sigset_t sigs;
    		//清空信号集
    		sigemptyset(&sigs);
    		//添加信号到信号集
    		sigaddset(&sigs,SIGINT);
    		//屏蔽SIGINT信号
    		sigprocmask( SIG_BLOCK,&sigs,0);
    
    		wait_mark=1;
    		signal(16,stop);        /*接收到软中断信号16,转stop*/
    		waiting( );
    		lockf(stdout,1,0);
    		printf("Child process 1 is killed by parent!\n");
    		lockf(stdout,0,0);
    		exit(0);
    	}
    	return 0;
    }
    
    void waiting( ) {
    	while(wait_mark!=0);
    }
    
    void stop( ) {
    	wait_mark=0;
    }
    
    

    运行结果

    程序创建两个子进程,用无名管道和有名管道两种方式实现父进程与子进程的数据通信。第一个子进程向管道写入“I am child 1”,第二个子进程向管道写入“I am child 2”。父进程从管道中读取两个子进程写入的数据并打印。要求先打印“I am child 1”,后打印“I am child 2”。

    方法一:使用一个信号,当pid1运行完了以后通知以下pid2

    方法二:直接在pid2加个sleep

    无名管道实现

    #include <unistd.h>
    #include <signal.h>
    #include <stdlib.h>
    #include <stdio.h>
    int pid1,pid2;
    void waiting( ),stop( );
    int wait_mark;
    main( ) {
    	int fd[2];
    	char outpipe[100],inpipe[100];
    	pipe(fd);                       /*创建一个管道*/
    	while ((pid1=fork( ))==-1);
    	if(pid1==0) {
    		lockf(fd[1],1,0);
    		sprintf(outpipe,"I am child 1");
    		/*把串放入数组outpipe中*/
    		write(fd[1],outpipe,50);     /*向管道写长为50字节的串*/
    		sleep(2);                 /*自我阻塞5秒*/
    		lockf(fd[1],0,0);
    		exit(0);
    	} else {
    		while((pid2=fork( ))==-1);
    		if(pid2==0) {
    			//增加一个接受信号
    			wait_mark=1;
    			signal(10,stop);
    			waiting();
    
    			lockf(fd[1],1,0);           /*互斥*/
    			sprintf(outpipe,"I am child 2");
    			write(fd[1],outpipe,50);
    			sleep(2);
    			lockf(fd[1],0,0);
    			exit(0);
    		} else {
    			wait(0);              /*同步*/
    			read(fd[0],inpipe,50);   /*从管道中读长为50字节的串*/
    			printf("%s\n",inpipe);
    			//增加一个发送信号
    			kill(pid2,10);
    
    			wait(0);
    			read(fd[0],inpipe,50);
    			printf("%s\n",inpipe);
    			exit(0);
    		}
    	}
    }
    void waiting( ) {
    	while(wait_mark!=0);
    }
    
    void stop( ) {
    	wait_mark=0;
    }
    

    运行结果

    有名管道实现

    #include <unistd.h>
    #include <signal.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <fcntl.h>
    
    int pid1,pid2;
    void waiting( ),stop( );
    int wait_mark;
    int main( ) {
    	int len;
    	char *filename = "fifo";
    	//创建一个管道文件mkfifo中filename为文件名,0666为八进制数,表示茶创建文件的权限
    	int res = mkfifo(filename,0666);
    	if(res < 0) {
    		perror("mkfifo error");
    		return -1;
    	}
    
    	//O_RDWR:以读写的方式打开
    	int fd = open(filename,O_RDWR);
    	if(fd < 0) {
    		perror("open error");
    		return -2;
    	}
    	
    	while ((pid1=fork( ))==-1);
    	if(pid1==0) {
    		/* pid1进程将字符串管道文件 */
    		char *str1 = "I am child 1";
    		//fd为打开的文件,str为字符串,strlen(str)为写入字符串的长度
    		int len = write(fd,str1,strlen(str1));
    		sleep(2);
    		/* pid1进程将字符串管道文件 */
    		exit(0);
    	} else {
    		while((pid2=fork( ))==-1);
    		if(pid2==0) {
    			//增加一个接受信号
    			wait_mark=1;
    			signal(10,stop);
    			waiting();
    			/** pid2进程将字符串管道文件 **/
    			char *str1 = "I am child 2";
    			int len = write(fd,str1,strlen(str1));
    			sleep(2);                 
    			/** pid2进程将字符串管道文件 **/
    			exit(0);
    
    		} else {
    			wait(0);              /*同步*/
    			//父进程读取pid1写的文件
    			char buf[128] = {0};
    			len = read(fd,buf,sizeof(buf) - 1);
    			printf("%s\n",buf);
    
    			//增加一个发送信号
    			kill(pid2,10);
    			wait(0);
    			//父进程读取pid2写的文件
    			len = read(fd,buf,sizeof(buf) - 1);
    			printf("%s\n",buf);
    			//销毁文件指针并删除文件
    			close(fd);
    			unlink(filename);
    
    			exit(0);
    		}
    	}
    	
    
    	return 0;
    }
    void waiting( ) {
    	while(wait_mark!=0);
    }
    
    void stop( ) {
    	wait_mark=0;
    }
    

    运行结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值