Linux进程间通信

来源:互联网 发布:淘宝假羽绒被 编辑:程序博客网 时间:2024/05/29 11:35

进程间通信(IPC)学习总结
一、进程间通信的必要性:
1、数据传输:一个进程需要将它的数据发送给另一个进程
2、资源共享:多个进程间需要共享资源。
3、通知事件:一个进程需要向另一个或一组进程发送消息,通知它们发生了某种事件。
4、进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有操作,并能够及时知道它的状态改变。
二、进程间通信方式:
1、管道(pipe)和有名管道(FIFO)
2、信号(Signal):用于通知接收进程有某种事件发生
3、消息队列:是一种消息的链接表,对进程的权限要求较高。
4、共享内存:可以使多个进程访问同一块内存空间,是最快的进程间通信方式。
5、信号量:主要是一种用于进程间以及同一进程的不同线程之间的同步手段。
6、套接字(socket):不同机器或者系统间的进程间通信。
三、进程间通信——管道
1、管道:管道是单向的、先进先出的,它把一个进程的输出和另一个进程的输入连接在一起。一个进程(写进程)在管道的尾部写入数据,另一个进程(读进程)从管道的头部读出数据。
2、管道分为无名管道和命名管道。
无名管道:主要用于父进程和子进程之间的通信。
命名管道:适用于同一系统的任意两个进程之间的通信。
3、无名管道
a、无名管道通过调用函数pipe来创建:
函数原型:int pipe(int fd[2]) 函数成功返回0,否则返回-1.
头文件:#include<unistd.h>
当一个管道建立时,它会创建两个文件描述符:fd[0]用于读取管道;fd[1]用于写入管道。一般文件I/O函数都可以用于管道的读写,比如:read、write等。
注:一个进程在由函数pipe创建一个管道后,一般再由fork函数创建一个子进程,然后通过无名管道进行父子进程之间的通信。
b、无名管道的读写:
管道的读取:
当管道的写端不存在时,程序则认为读到了数据的结尾,读函数返回的读出字节数为0。
当管道的写端存在时,读出数据的字节数根据管道中现有的数据字节数决定。
管道的写入:
只有在管道的读端存在时,向管道写入数据才有意义,否则,向管道写入数据的进程将收到内核传来的SIGPIPE信号。
父子进程在运行时,它们的先后顺序不能保证,为了保证父子进程关闭了相应的文件描述符,可以使用sleep()解决。
向管道写入数据时,管道缓冲区一有空闲区域,写进程就会试图向管道写入数据,如果读进程不读取管道缓冲区中的数据,写操作将会阻塞。
注意:必须在系统调用fork( )前调用pipe( ),否则子进程将不会继承文件描述符。
当使用半双工管道时,任何关联的进程都必须共享一个相关的祖先进程。因为管道存在于系统内核之中,所以任何不在创建管道的进程的祖先进程之中的进程都将无法寻址它。而在命名管道中却不是这样。
4、命名管道
a、命名管道通过mkfifo函数进行创建.
函数原型:int mkfifo(const char* pathname,mode_t mode)
pathname :命名管道文件名,mode:用来规定命名管道的读写权限
这里写图片描述
注:由于普通文件的读写时不会出现阻塞问题,而在管道的读写中却有阻塞的可能,这里的非阻塞标志可以在open()函数中设定为O_NONBLOCK。
对于读进程:若该管道是阻塞打开,且当前FIFO内没有数据,则对读进程而言将一直阻塞到有数据写入。若该管道是非阻塞打开,则不论FIFO内是否有数据,读进程都会立即执行读操作。即如果FIFO内没有数据,则读函数将立刻返回0。
对于写进程:若该管道是阻塞打开,则写操作将一直阻塞到数据可以被写入。若该管道是非阻塞打开而不能写入全部数据,则读操作进行部分写入或者调用失败。
b、管道删除:命名管道的删除可以用unlink函数实现
函数原型:int unlink(const char * pathname) 头文件:#include