进程间通信方法
- 管道
- 共享内存
- 消息队列
- 信号量
- FIFO,命名管道
管道通信
进程之间需要进行同步通信,但是如果按照传统的fork进程,会使新建的进程的数据再复制一份,因此就会导致无法通信。
Linux里面管道通信主要使用pipe函数进行通信。
pipe函数使用方法:
这个函数生成的管道是半双工的,只能单向通信,如果想要双向通信,需要建立两根管道。数据只能从管道的一端写入,从另一端读出。
int pipe(int fd[2]);
这里的fd表示文件描述符,构成管道两端,往fd[1]里面写数据,入口,fd[0]是读数据,出口。
write(fd[1],"hello,world",10);
read(fd[0],buffer,sizeof(buffer));
默认情况下,这一对文件描述符都是阻塞的。此时,如果我们用read系统调用来读取一个空的管道,则read将被阻塞,直到管道内有数据可读;如果我们用write系统调用往一个满的管道中写数据,则write也将被阻塞,直到管道内有足够的空闲空间可用(read读取数据后管道中将清除读走的数据)。当然,用户可以将fd[0]和fd[1]设置为非阻塞的。
共享内存
由系统分配一块进程都可以访问的内存,通过这块内存,可以进行读/写操作。
使用共享内存的方法:
- 创建或获取一段共享内存
- 将得到的共享内存映射到进程的地址空间
- 访问共享内存
- 将共享内存从当前的进程地址空间中分离
- 删除该段共享内存空间。
在共享内存方面需要使用的函数:
shmget,shmctl,shmdt,shmat
在使用shmget的时候需要使用唯一标志键值,使用ftok函数来生成,该函数的第一个参数是文件路径名,第二个是用户定义的整数值。
通过这五个函数可以实现上述过程。
信号量
主要是通过p,v操作来实现的。p表示申请一个信号量,v表示释放一个信号量
这个主要是为了防止多个程序同时访问一个共享资源而引发的一系列问题,我们需要一种方法,可以生成并使用一个变量来授权,在任意时刻只能有一个执行线程访问代码的临界区域。
使用的函数有:semget,semctl,semop,sembuf
注意这个sembuf是一个结构体,例子:
sembuf sop{
.semnum=0,
.semop=1
};
消息队列
消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构。我们可以通过发送消息来避免命名管道的同步和阻塞问题。但是消息队列与命名管道一样,都有数据块的最大长度限制。
需要使用的API有:
msgget,msgflg,msgsnd,msgrcv,msgctl.
注意这个函数,在有的操作系统中可能会没有实现,所以要注意使用时操作系统是否有定义该函数。
fifo
这是一个命名管道
通过定义一个fifo类型的文件来进行进程间的同步和通信。
使用方法:
int mkfifo(const char*pathname,mode_t mode);
然后就可以使用open来对管道进行传输数据和使用了。
主要用来在没有亲戚关系的进程之间使用,弥补了之前pipe需要在有亲缘关系的进程中使用的不足。本质就是Linux中文件,毕竟在Linux中万物皆文件。但是要注意mode是我们需要给的权限,例如:
在open时,可以使用O_RONLY,O_WRONLY等宏来进行设置。