Linux进程和线程间IPC机制

Linux进程间IPC

1.管道(Pipe)及有名管道(named pipe):

1、管道是半双工的,要实线读写需建立两根管道;
2、匿名管道用于父子进程或者兄弟进程之间(如forkexec创建的进程),命名管道允许没有亲缘关系的进程间通信;
3、单独构成一种独立的文件系统,它不是普通的文件,不属于某种文件系统,单独构成一种文件系统,并且只存在与内存中;
4、一个进程向管道中写的内容被管道另一端的进程读出。写内容每次都添加在管道缓冲区末尾,读每次从缓冲区头部读出数据。
5、管道的缓冲区是有限的(管道制存在于内存中,在管道创建时,为缓冲区分配一个页面大小);
6、管道所传送的是无格式字节流,这就要求管道的读出方和写入方必须事先约定好数据的格式。
7、管道只能在本地计算机中使用,而不可用于网络间的通信。
8、当写入数据量不大于PIPE_BUF时,linux将保证写入的原子性,当要写入数据量大于PIPE_BUF时,linux将不再保证写入的原子性。

2.信号(Signal):

信号机制是unix系统中最为古老的进程之间的通信机制,用于一个或几个进程之间传递异步信号。信号可以有各种异步事件产生,比如键盘中断等。shell也可以使用信号将作业控制命令传递给它的子进程。
int kill(pid_t pid,int sig); //kill函数向进程号为pid的进程发送信号

3.报文(Message)队列(消息队列):

1.msgqueue是内核地址空间中的内部链表,通过linux内核在各个进程传递内容,每个消息队列用IPC标识符唯一标识;
2.msgqueue可承载8192+4Bytes的格式化消息,与管道只能承载无格式字符流不同;
3.消息从末端加入,可依次出队也可按类型出队;
4.消息队列可独立于发送和接收进程存在,免去了同步命名管道打开和关闭时产生的麻烦;
5.同时通过发送消息还可以避免命名管道的同步和阻塞问题,不需要由进程自己来提供同步方法;

4.信号量(Semaphore):

主要作为进程间以及同一进程不同线程之间的同步手段。

5.共享内存(Memory Map)

共享内存是在多个进程之间共享内存区域的一种进程间的通信方式,由IPC为进程创建的一个特殊地址范围,它将出现在该进程的地址空间中.其他进程可以将同一段共享内存连接到自己的地址空间中.所有进程都可以访问共享内存中的地址,就好像它们是malloc分配的一样.如果一个进程向共享内存中写入了数据,所做的改动将立刻被其他进程看到。共享内存是IPC最快捷的方式,因为共享内存方式的通信没有中间过程,而管道、消息队列等方式则是需要将数据通过中间机制进行转换。共享内存方式直接将某段内存段进行映射,多个进程间的共享内存是同一块的物理空间,仅仅映射到各进程的地址不同而已,因此不需要进行复制,可以直接使用此段空间。

6.内存映射文件:

1、内存映射文件:
内存映射文件,是由一个文件到一块内存的映射。内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址的区域,同时将物理存储器提交给此区域,内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而且对该文件进行操作之前必须先对文件进行映射。使用内存映射文件处理存储于磁盘上的文件时,不必再对文件执行I/O操作。每一个使用该机制进程通过把同一个共享文件映射到自己的进程地址空间来实现多个进程间的通信(这里类似于共享内存,只要有一个进程对这块映射文件的内存进行操作,其他进程也能够马上看到).
2.内存映身文件拷备效率:
使用内存映射文件不仅可以实现多个进程间的通信,还可以用于处理大文件提高效率。因为我们普通的做法是把磁盘上的文件先拷贝到内核空间的一个缓冲区再拷贝到用户空间(内存),用户修改后再将这些数据拷贝到缓冲区再拷贝到磁盘文件,一共四次拷贝。如果文件数据量很大,拷贝的开销是非常大的。那么问题来了,系统在在进行内存映射文件就不需要数据拷贝?mmap()确实没有进行数据拷贝,真正的拷贝是在在缺页中断处理时进行的,由于mmap()将文件直接映射到用户空间,所以中断处理函数根据这个映射关系,直接将文件从硬盘拷贝到用户空间,所以只进行一次数据拷贝。效率高于read/write。
3.共享内存和内存映射文件的区别:
内存映射文件是利用虚拟内存把文件映射到进程的地址空间中去,在此之后进程操作文件,就像操作进程空间里的地址一样了,比如使用c语言的memcpy等内存操作的函数.这种方法能够很好的应用在需要频繁处理一个文件或者是一个大文件的场合,这种方式处理IO效率比普通IO效率要高共享内存是内存映射文件的一种特殊情况,内存映射的是一块内存,而非磁盘上的文件。共享内存的主语是进程(Process),操作系统默认会给每一个进程分配一个内存空间,每一个进程只允许访问操作系统分配给它的哪一段内存,而不能访问其他进程的。而有时候需要在不同进程之间访问同一段内存,怎么办呢?操作系统给出了创建访问共享内存的API,需要共享内存的进程可以通过这一组定义好的API来访问多个进程之间共有的内存,各个进程访问这一段内存就像访问一个硬盘上的文件一样。

7.网络Socket/UNIX Domain Socket

socket API原本是为网络通讯设计的,但后来在socket的框架上发展出一种IPC机制,就是UNIX Domain Socket。虽然网络socket也可用于同一台主机的进程间通讯(通过loopback地址127.0.0.1),但是UNIX Domain Socket用于IPC更有效率:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。这是因为,IPC机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。UNIX Domain Socket也提供面向流和面向数据包两种API接口,类似于TCP和UDP,但是面向消息的UNIX Domain Socket也是可靠的,消息既不会丢失也不会顺序错乱。
  UNIX Domain Socket是全双工的,API接口语义丰富,相比其它IPC机制有明显的优越性,目前已成为使用最广泛的IPC机制,比如X Window服务器和GUI程序之间就是通过UNIX Domain Socket通讯的。
  使用UNIX Domain Socket的过程和网络socket十分相似,也要先调用socket()创建一个socket文件描述符,address family指定为AF_UNIX,type可以选择SOCK_DGRAM或SOCK_STREAM,protocol参数仍然指定为0即可。
  UNIX Domain Socket与网络socket编程最明显的不同在于地址格式不同,用结构体sockaddr_un表示,网络编程的socket地址是IP地址加端口号,而UNIX Domain Socket的地址是一个socket类型的文件在文件系统中的路径,这个socket文件由bind()调用创建,如果调用bind()时该文件已存在,则bind()错误返回。

8 消息总线(比如zeromq)

9 其他中间件(比如redis, memchache, 数据库等)

Linux线程间IPC

https://blog.csdn.net/a987073381/article/details/52029070

TCPIP

http://www.cnblogs.com/Jessy/p/3535612.html

猜你喜欢

转载自blog.csdn.net/dodonei/article/details/79957610