Linux下父進程向子進程發送信號


Linux下父進程向子進程發送信號

需要用到的函數:

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;
}

運行結果

1588265576365

程序創建兩個子進程,用無名管道和有名管道兩種方式實現父進程與子進程的數據通信。第一個子進程向管道寫入“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;
}
運行結果

1588266061991

有名管道實現

#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;
}
運行結果

1588266079824


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM