1. 程式人生 > >Linux-程序通訊-管道/訊號

Linux-程序通訊-管道/訊號

pipe

    無名管道,只能用於親緣關係的程序間通訊,半雙工,固定讀fd[0],寫fd[1],檔案I/O實現;

    當管道中午資料時,讀阻塞;

    當寫緩衝區滿時又不被讀走,此時寫阻塞;

    例項:父程序讀阻塞,子程序寫成功然後父程序讀成功返回。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#define MAX 1024

int main()
{
	int fd[2];
	int ret = pipe(fd);
	if(0 > ret)
	{
		perror("pipe");
		exit(-1);
	}

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

	if(0 == pid)
	{
		printf("child process\n");
		sleep(3);

		char buf[] = "hello world";

		ret = write(fd[1], buf, sizeof(buf)-1);
		if(0 > ret)
		{
			perror("write");
			exit(-1);
		}
	}

	if(0 < pid)
	{
		char rbuf[MAX];
		memset(rbuf, 0, MAX);
		printf("parent process\n");
		ret = read(fd[0], rbuf, MAX);
		if(0 > ret)
		{
			perror("read");
			exit(-1);
		}

		printf("read num:%d,buf:%s\n", ret, rbuf);
	}

	exit(0);
}

fifo

    有名管道,可實現不相干的程序間通訊,檔案I/O操作。

    讀寫阻塞通過O_NONBLOCK控制,表示非阻塞,下面例子是寫非阻塞,讀阻塞;先執行讀程序(被阻塞),再執行寫程序,一切正常;若先執行寫程序,open呼叫將返回-1,開啟失敗。

#define FIFONAME "/tmp/myfifo"
mkfifo(FIFONAME, O_CREAT)

int fd = open(FIFONAME, O_WRONLY|O_NONBLOCK, 0);
char buf[] = "hello FIFO test.";
write(fd, buf, sizeof(buf)

char buf_r[100];
memset(buf_r,0,sizeof(buf_r));
int fd = open(FIFONAME, O_RDONLY, 0);
read(fd,buf_r, 100)

unlink(FIFONAME)

訊號通訊 kill/raise

    中斷控制,非同步通訊方式,軟中斷核心控制;

    kill把訊號傳送給程序或程序組;int kill(pid_t pid, int signo);成功則返回0, 出錯則返回-1;

    raise把訊號傳送給(程序)自身;int raise(int signo);成功則返回0, 出錯則返回-1。

    kill(getppid(), SIGKILL);殺死父程序;

    raise(SIGKILL);殺死自己程序;

wait函式

    wait函式阻塞自己程序,直到自己的某一個子程序退出函式才返回;

    pid_t wait(int *status),status儲存子程序退出時的一些狀態,返回子程序的id,

    pid_t waitpid(pid_t pid, int *status, int options),pid>0時,只等待程序ID等於pid的子程序;pid=-1時,等待任何一個子程序退出;pid=0時,等待同一個程序組中的任何子程序;pid<-1時,等待一個指定程序組中的任何子程序,這個程序組的ID等於pid的絕對值。

alarm函式

    alarm函式設定一個定時器,時間到後向當前程序傳送一個SIGALARM終止訊號;如果alarm()前已經設定了一個鬧鐘,可以呼叫alarm(0)來取消此鬧鐘,並返回剩餘時間;如果想重新設定一個鬧鐘,可以alarm(n),會取消前的鬧鐘並返回剩餘時間,然後重新開始倒計時。

pause函式

    pause函式使程序或執行緒進入睡眠狀態,直到收到訊號。

signal函式

    註冊訊號處理函式,函式原型:sighandler_t signal(int signum, sighandler_t handler);

    signum是我們要處理的訊號,系統訊號可通過命令kill -l檢視:

    handler是收到訊號後的處理動作,SIG_ING是收到訊號後忽略,比如signal(SIGINT, SIG_IGN);收到中斷訊號忽略,那麼用Ctrl+C就不能中斷程式,此時可用Ctrl+\傳送Quit訊號;

    handler還可以是函式,收到訊號後執行函式,如下面的例子:收到訊號後就去執行handler函式,執行完後前面的函式繼續執行。

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#define _GNU_SOURCE

#define MAX 9
char arr[MAX];

void unrecall(int val)
{
	for(int i = 0; i < MAX; i++)
	{
		arr[i] = val+i;
		printf("NO %d.%d: %d\n",val, i, arr[i]);
		sleep(1);
	}
}

void handler(int sig)
{
	 unrecall(sig);
}

int main()
{
	if(SIG_ERR == signal(SIGUSR1, handler))
		perror("signal");

	pid_t pid = fork();
	if(0 > pid)
	{
		perror("fork");
		exit(-1);
	}
	else if(0 == pid)
	{
		sleep(5);
		kill(getppid(), SIGUSR1);
	}
	else if(0 < pid)
	{
		printf("SIGUSR1=%d\n", SIGUSR1);//10
		unrecall(1);

		for(int i = 0; i < MAX; i++)
		{
			printf("all:NO.%d: %d\n", i, arr[i]);
		}

	}

	exit(0);
}

    傳送訊號可用kill和raise函式。