进程间通信方式有管道,共享内存,消息队列,信号量。
管道是IPC的一种方式,管道属于一种伪文件,实则是一种 内核缓冲区。
在这里对三种通信方式做一个总结:
1.单工通信方式:只能由一端到达另一端,不能反过来传输!发送端与接收端是固定的,是不可变的。
2.半双工通信方式:读端->写端,读端可以变成写端,写端也可以变成读端。但同一时刻只能由一端到另一端,同一时刻,不能双向传递,只能说进行分时轮流交替进行,说白了就是一种可以选择方向的单工通信方式。
3.全单工通信方式:指同一时刻,数据可以在信道上双向传输,即可以A->B也可以B->A,即是一种双向同时通信!
管道又分为匿名管道与命名管道,匿名管道只能应用于具有亲缘关系的进程间,例如父子进程与兄弟进程之间。管道就是一种一个进程到另一个进程之间的媒介,把两个进程连接在一起
匿名管道
匿名管道是内核中的一块缓冲区, 其本质就是一个文件, 但这个文件没有名字, 所以称之为"匿名管道". 但一个文件没有名字的话,
不同进程又如何知道要访问哪一块内存来实现进程间通信呢 ? 实际上这是利用了父进程创建子进程时, 子进程的task_struct(PCB)
会获取到大部分父进程task_struct中的信息, 其中就包括父进程创建的匿名管道时返回的两个匿名管道的文件描述符, 这样,子进程
也就能通过这两个匿名管道的文件描述符访问匿名管道了. 也就是说匿名管道实现的进程间通信只能限制于有亲缘关系的进程间
才能通信, 也就是只能用于具有公共祖先的进程之间的通信.
int pipe(fd[2])建立一个匿名管道。
fd[0]是管道的读端,fd[1]是管道的写端!
当父子之间应用匿名管道通信时,1.父进程写的时候要关闭父进程的读端,同时关闭子进程的写端!2.父进程要读的时候关闭父进程的写端,同时关闭子进程的读端 !
pipe函数返回值0表示成功,-1表示失败!
命名管道(named pipe,fifo):
内核中的缓冲区具有标识符---可以用于同意主机上的任意进程间通信。
int mkfifo(const char *pathname, mode_t mode)
pathname:创建一个具有pathname文件名的FIFO文件,mode是设置文件的权限
若管道中所有读端被关闭,则继续write就会使进程收到SIGPIPE信号,从而导致触发异常退出进程 / 2.若管道中所有写端被关闭,则继续read在读取完数据不会阻塞,而是返回0。如果写端并没有关闭,则read会出现阻塞。
管道自带同步与互斥的属性:
同步表现:
1.当读数据的时候,数据缓冲区没数据,则会进行阻塞。
2.当写数据的时候,数据缓冲区满了,则会发生阻塞。
互斥表现在:
1.同一时刻,只有一个进程对临界资源进行访问。保证了临界资源的安全性。
2.对管道内数据进行操作时,大小不能超过PIPE_BUF,保证了操作的原子性。
共享内存 :
共享内存就是映射了一块能被其他进程访问的内存区域,这个区域可以被多个进程共同访问,即由一个进程创建,但可以由多个进程共同访问,是最快的IPC(进程间通信)方式。它是针对其他IPC方式效率低下而设计的。他往往与信号量进行配合使用,从而实现进程的同步与互斥。
消息队列:
消息队列是消息的链表,存放在内核中并由消息队列标识符标识.消息队列克服了信号传递信息少,管道只能承载无格式字节流以及缓冲区大小受限等特点.消息队列是UNIX下不同进程之间可实现共享资源的一种机制,UNIX允许不同进程将格式化的数据流以消息队列形式发送给任意进程.对消息队列具有操作权限的进程都可以使用msget完成对消息队列的操作控制.通过使用消息类型,进程可以按任何顺序读信息,或为消息安排优先级顺序.
信号量:
信号量是一个计数器,可以用来控制多个线程对共享资源的访问.,它不是用于交换大批数据,而用于多线程之间的同步.它常作为一种锁机制,防止某进程在访问资源时其它进程也访问该资源.因此,主要作为进程间以及同一个进程内不同线程之间的同步手段.
Linux提供了一组精心设计的信号量接口来对信号进行操作,它们不只是针对二进制信号量,下面将会对这些函数进行介绍,但请注意,这些函数都是用来对成组的信号量值进行操作的。它们声明在头文件sys/sem.h中。
semget函数
它的作用是创建一个新信号量或取得一个已有信号量
semop函数
它的作用是改变信号量的值
semctl函数
该函数用来直接控制信号量信息