嵌入式Linux并发程序设计,进程间通信方式(七种),无名管道,无名管道特点,无名管道创建pipe(),获取管道大小,管道断裂

1,Linux下的进程间通信机制

Linux下的进程间通信机制 应用
早期UNIX进程间通信方式
(很多是从Unix继承的)
无名管道(pipe) 本地通信,用于一台计算机内部不同进程之间的通信
有名管道 (fifo)
信号(signal)
System V IPC
(系统5的IPC机制)
共享内存(share memory)
消息队列(message queue)
信号灯集(semaphore set)
套接字(socket) 既可以进行本地通信,更多的是多台主机之间通过网络通信

2,无名管道

在这里插入图片描述

  1. 线程共享同一个地址空间,所以线程之间交换数据很方便,最简单的就是建一个全局的缓冲区
  2. 每个进程有自己独立的地址空间,是私有的,有自己的代码,有自己的数据,所以进程之间要通信,要交换数据就需要专门的通信机制来实现,无名管道就是其中最简单的一种

无名管道特点

  1. 只能用于具有亲缘关系的进程(父子进程,祖孙进程,兄弟进程)之间的通信:管道创建好之后,虽然返回两个文件描述符,但是无名管道不像普通文件有路径,在文件系统中是不可见的,仅仅在内存中存在,并且无名管道是某一个进程创建的,其他进程想要打开无名管道,只能通过继承的方式打开其他进程创建的无名管道
  2. 单工的通信模式,具有固定的读端和写端:如父进程写管道,子进程读管道;或子进程写管道,父进程读管道;双向的数据通信要通过两个无名管道来实现
  3. 无名管道创建时会返回两个文件描述符,分别用于读写管道

创建无名管道pipe()

#include <unistd.h>
int pipe(int pfd[2]);

  1. 成功时返回0,失败时返回EOF
  2. pfd 包含两个元素的整形数组,用来保存文件描述符
  3. pfd[0]用于读管道;pfd[1]用于写管道

无名管道通信

在这里插入图片描述

3,无名管道示例

子进程1和子进程2分别往管道中写入字符串;父进程读管道内容并打印;

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>

int main(void) 
{
	pid_t pid1, pid2;
	char buf[32];
	int pfd[2];
	if (pipe(pfd) < 0) //先创建无名管道,后创建子进程
	{
		perror(“pipe”); exit(-1);
	}
	if ((pid1 = fork()) < 0) 
	{
		perror(“fork”);  exit(-1);
	}
	else if (pid1 == 0) 
	{          //  子进程1
		strcpy(buf, “I’m process1”);
		write(pfd[1], buf, 32);
		exit(0);   
	}
	else 
	{             //  父进程
		if ((pid2 = fork()) < 0) 
		{
			perror(“fork”); exit(-1);
		}
		else if (pid2 == 0) 
		{        //  子进程2
			sleep(1);
			strcpy(buf, “I’m process 2);
			write(pfd[1], buf, 32);
		}  
		else 
		{        //  父进程
			wait(NULL);//进程回收,哪个先结束回收哪个
			read(pfd[0], buf, 32);//管道中的内容读走之后,管道中就没内容了
			printf(%s\n”, buf);
			wait(NULL);
			read(pfd[0], buf, 32);
			printf(%s\n”, buf);
		}
	}
	return  0;
}   

4,无名管道详解

操作 情况 状态
读无名管道 写端存在
(至少有一个进程可以通过文件描述符写管道)
有数据 管道中的数据比进程读管道指定的大小多 read返回实际读取的字节数
管道中的数据比进程希望要读取的数据少
无数据 进程读阻塞
写端不存在 有数据 read返回实际读取的字节数
无数据 (不阻塞)read返回0
写无名管道 读端存在
(至少有一个进程可以通过文件描述符读管道内容)
有空间 write返回实际写入的字节数
无空间 空间不足(管道中的剩余空间比进程写管道需要的空间小) 系统不保证原子操作(能写多少写多少,然后进程写阻塞)
无空间(经过多次写之后,管道中一点空间都没有了) 进程写阻塞
读端不存在 有空间 管道断裂(系统不允许任何进程写一个没有读端的管道)
无空间

如何获取无名管道的大小?

  1. 循环写入管道,直到阻塞
  2. 统计循环次数
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, const char *argv[])
{
	int count=0,num=0,bytes=0,pfd[2];
	char buf[1024];

	if(pipe(pfd) < 0)
	{
		perror("pipe");
		exit(-1);
	}
	while(1)
	{
		bytes = write(pfd[1],buf,1024);
		num += bytes;
		printf("num:%d   bytes:%d    wrote %d k bytes\n",num,bytes,++count);
	}

	return 0;
}
linux@linux:~/test/pthread$ gcc pipe_size.c -o pipe_size.out
linux@linux:~/test/pthread$ ./pipe_size.out 
num:1024   bytes:1024    wrote 1 k bytes
num:2048   bytes:1024    wrote 2 k bytes
.
.
.
num:64512   bytes:1024    wrote 63 k bytes
num:65536   bytes:1024    wrote 64 k bytes

  • Linux创建的管道缺省大小64k字节

如何验证管道断裂(进程被信号结束)?

  1. 子进程写管道
  2. 父进程回收
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, const char *argv[])
{
	pid_t pid;
	int pfd[2],status;
	char buf[32];

	if(pipe(pfd) < 0)
	{
		perror("pipe");
		exit(-1);
	}
	close(pfd[0]);
	if((pid = fork()) < 0)
	{
		perror("fork");
		exit(-1);
	}
	else if(pid == 0)
	{
		write(pfd[1],buf,32);
		exit(0);
	}
	else
	{
		wait(&status);
		printf("status %#x\n",status);
	}

	return 0;
}
linux@linux:~/test/pthread$ gcc pipe_broken.c -o pipe_broken.out
linux@linux:~/test/pthread$ ./pipe_broken.out 
status 0xd
  • status的值不为零,说明进程被信号打断,status的值就是信号的类型

使用kill -l查看当前系统中所有的信号类型

linux@linux:~/test/pthread$ kill -l
 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
 6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX	
  • 0xd是13,可以看到13对应的信号类型是SIGPIPE,这个信号通常就代表管道断裂

猜你喜欢

转载自blog.csdn.net/m0_37542524/article/details/83896501