Linux-进程通信-管道/信号

pipe

    无名管道,只能用于亲缘关系的进程间通信,半双工,固定读fd[0],写fd[1],文件I/O实现;

    当管道中无数据时,读阻塞;

    当写缓冲区满时又不被读走,此时写阻塞;

    实例:父进程读阻塞,子进程写成功然后父进程读成功返回。

#include 
#include 
#include 
#include 

#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查看:

Linux-进程通信-管道/信号_第1张图片

    handler是收到信号后的处理动作,SIG_ING是收到信号后忽略,比如signal(SIGINT, SIG_IGN);收到中断信号忽略,那么用Ctrl+C就不能中断程序,此时可用Ctrl+\发送Quit信号;

    handler还可以是函数,收到信号后执行函数,如下面的例子:收到信号后就去执行handler函数,执行完后前面的函数继续执行。

#include 
#include 
#include 
#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函数。

你可能感兴趣的:(Linux)