【UNIX】什麼是進程間FIFO通信以及信號通信

上篇中的無名管道通信是父子進程之間的通信,限定了進程之間的通信,從而就有了有名管道,它可以使不同進程之間進行通信,有名管道可以通過指定路徑名來指出,兵長文件系統中可見。進程通過文件IO來操作有名管道,有名管道遵從先進先出的原則,但是不支持lseek函數。

1)int mkfifo(const char *pthname,mode_t mode)創建有名管道,

2)在內核中創建對象,但沒有打開讀寫,有名管道的讀寫要自己打開,

3)文件對象在文件系統中創建文件節點,

4)在兩個進程中,只會創建一次,若有節點則不會創建,第二次創建會返回錯誤信息,

FIFO的一般形式函數:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

/* open a read endpoint on a FIFO */
int fifo_read (const char *pathname);
/* open a write endpoint on a FIFO */
int fifo_write(const char *pathname);
/* print usage info */
void usage(const char *argv0);

int main(int argc,char *argv[])
{
	if (argc < 3) {
		usage(argv[0]);
		return -1;
	}
	
	if ('r' == argv[1][0]) {
		if (fifo_read(argv[2]) < 0) {
			return -1;
		}
	} else if ('w' == argv[1][0]) {
		if (fifo_write(argv[2]) < 0) {
			return -1;
		}
	} else {
		usage(argv[0]);
		return -1;
	}

	return 0;
}

int fifo_read (const char *pathname)
{
	int fd;
	
	/*
	 * Ignore EEXIST for this case.
	 * EEXIST means the FIFO has been created already.
	 */
	if (mkfifo(pathname, 0666) < 0) {
		if (EEXIST == errno) {
			printf("FIFO has been created at %s\n",
				pathname);
		} else {
			perror("mkfifo error");
			return -1;
		}
	} else {
		printf("FIFO was created at %s\n", pathname);
	}

	if ((fd = open(pathname, O_RDONLY)) < 0) {
		perror("open for read w/ block error");
		return -1;
	}
	
	printf("open read endpoint success.\n");
	
	return 0;
}

int fifo_write(const char *pathname)
{
	int fd;
	
	/*
	 * Ignore EEXIST for this case.
	 * EEXIST means the FIFO has been created already.
	 */
	if (mkfifo(pathname, 0666) < 0) {
		if (EEXIST == errno) {
			printf("FIFO has been created at %s\n",
				pathname);
		} else {
			perror("mkfifo error");
			return -1;
		}
	} else {
		printf("FIFO was created at %s\n", pathname);
	}
	
	if ((fd = open(pathname, O_WRONLY)) < 0) {
		perror("open for write  w/ block error");
		return -1;
	}
	
	printf("open write endpoint success.\n");
	
	return 0;
}

void usage(const char *argv0)
{
	printf( "Usage : %s \n"
		"\n"
		"  r: create read endpoint\n"
		"  w: create write endpoint\n"
		":\n"
		"  path to the FIFO file in filesystem.\n"
		, argv0);	
}

信號通信

1)信號通信是在軟件層次上對中斷機制的一種模擬,是一種異步通信方式。

信號可以直接進行用戶空間進程和內核進程之間的交互,內核進程也可以利用它來通知用戶空間進程發生了哪些系統事件,

若果該進程當前處於未執行的狀態,該信號就由內核保存起來,直到該進程恢復執行再傳遞給它,若果一個信號被進程設置爲阻塞,則該信號的傳遞被延遲,直到阻塞被取消才傳遞給進程。

2)信號的生命週期


4)信號在內核中的形式:

1 信號的發生pending 

2 信號在進程中註冊

3 信號的投遞(執行和註銷):執行信號的動作稱爲信號的投遞

//

信號的未決:信號保存在內核中,直到信號被處理,返回給用戶態處理

信號的阻塞block

信號的部署:就是處理信號的函數(可以自己制定)信號的處理函數在用戶態進行處理,使用信號的阻塞,調用signal函數和pause函數,

內核信號的處理是在特定時間片才執行的(在內核進程退出的前夜統一處理多數信號,返回給用戶進程處理過程叫投遞)

信號的部署,就是通過系統特定的信號集,比如SIGINT/SIGQUIT/這些系統信號不被CTRL+C處理掉,但可以被KILL殺死


3)用戶進程對信號的響應方式:

1 忽略信號:對信號不做任何處理,但是有兩個信號不能忽略,就是SIGKILL和SIGSTOP,

2 捕捉信號:定義信號處理函數,當信號發生時,執行響應額處理函數,

3 執行缺省操作:Linux對每種信號都規定了默認操作。

3)信號的使用場合:

後臺進程需要使用信號,例如xinetd   

若果兩個進程沒有親緣關係,無法使用無名管道

若果兩個進程只有只能使用標準輸入和標準輸出,則不可以使用有名管道。


信號的部署函數的一般形式:


#include
#include
#include
#include
#include
#include

pid_t pid;

void func1(int sign)
{
	pid_t ppid = getppid();
	if (sign == SIGINT)
		kill(ppid,SIGUSR1);
	if (sign == SIGQUIT)
		kill(ppid,SIGUSR2);
	if(sign == SIGUSR1){
		printf("please get off the bus \n");
		kill(ppid,SIGKILL);
	}
	exit(0);
}

void func2(int sign)
{
	if (sign == SIGUSR1)
		printf("let is gogogo\n");
	if (sign == SIGUSR2)
	printf("stop the bus \n");
	if (sign == SIGTSTP)
		kill(pid,SIGUSR1);
	
}

int main ()
{
	printf("waiting for singal SIGINT or SIGQUIT\n");

	 pid = fork();

	 if (pid == -1){
		perror("fork");
		exit (-1);
	 }

	if (pid > 0){
		
		signal(SIGTSTP,func2);
		signal(SIGINT,SIG_IGN);	
		signal(SIGQUIT,SIG_IGN);
		signal(SIGUSR1,func2);
		signal(SIGUSR2,func2);
		pause();
		
	}

	if (pid == 0){
		signal(SIGINT,func1);
		signal(SIGQUIT,func1);
		signal(SIGTSTP,SIG_IGN);
		signal(SIGUSR1,func1);
		signal(SIGUSR2,SIG_IGN);
		pause();	
	}	
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章