一、现在在Linux中使用较多的进程间通信方式主要有以下几种:
(1)管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道除具有管道所觉有的功能外,它还允许无亲缘关系进程间的通信。
(2)信号(Signal):信号是在软件层次上对中断机制的一种模拟,它是比较复杂的通信方式,用于通知进程有某事件发生,一个进程收到一个信号与处理器收到一个中断请求效果上可以说是一样的。
(3)消息队列(Message Queue):消息队列是消息的链接表,包括Posix消息队列和Syetem V消息队列。它克服了前两种通信方式中信息量有限的缺点,具有写权限的进程可以按照一定的规则向消息队列中添加新消息;对消息队列有度权限的进程可以从消息队列中读取消息。
(4)共享内存(Shared memory):可以说这是最有用的进程间通信方式。它使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据的更新,这种通信方式需要依靠某种同步机制,如互斥锁和信号量等。
(5)信号量(Semaphore):主要作为进程之间以及同一进程的不同线程之间的同步和互斥手段。
(6)套接字(Socket):这是一种更为一般的进程间通信机制,它可用于网络中不同机器之间的进程间通信,应用非常广泛。
二、管道
1.无名管道
(1)无名管道创建和关闭
无名管道是基于文件描述符的通信方式,当一个管道建立时,它会创建两个文件描述符fds[0]和fds[1],其中fds[0]固定用于读管道,fds[1]固定用于写管道,这样就构成半双工的通道。而关闭无名管道只需将这两个文件描述符通过close()关闭。
(2)无名管道创建函数——pipe()
所需头文件 | #include <unistd.h> |
---|---|
函数原型 | int pipe(int fd[2]) |
函数传入值 | fd[2]:管道的两个文件描述符,之后就可以直接操作这两个文件描述符 |
函数返回值 | 成功:0 |
失败:-1 |
(3)无名管道读写说明
通常父进程先是创建一个管道,再通过fork()函数创建一个子进程,该子进程会继承父进程中所创建的管道,此时父进程有读写两个文件描述符,子进程也有两个文件描述符。
“子进程写入父进程读取”:子进程的读描述符关闭,父进程的写描述符关闭。
“父进程写入子进程读取”:子进程的写描述符关闭,父进程的读描述符关闭。
(4)使用实例
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#define BUFF_SIZE_MAX 256
#define DELAY_TIME 1
int main()
{
pid_t pid;
pid_t fds[2];
char buff[BUFF_SIZE_MAX];
const char data[] = "Pipe test Program";
int real_read,real_write;
if(pipe(fds) < 0)
{
printf("pipe error.\n");
exit(1);
}
pid = fork();
if(pid == -1)
{
printf("fork error.\n");
exit(1);
}
else if(pid == 0)
{
memset((void *)buff,0,BUFF_SIZE_MAX);
sleep(DELAY_TIME * 3);
close(fds[1]);
if((real_read = read(fds[0],buff,BUFF_SIZE_MAX)) > 0)
{
printf("Child read:%s\n",buff);
}
close(fds[0]);
exit(0);
}
else
{
close(fds[0]);
sleep(1);
if((real_write = write(fds[1],data,sizeof(data))) > 0)
{
printf("Father write:%s\n",data);
}
close(fds[1]);
waitpid(pid,NULL,0);
exit(0);
}
}
2.标准流管道
(1)标准流管道函数说明