Linux进程通信与同步
提供几种机制方便进程之间进行数据交换或者进程之间的同步
方式:
- pipe管道
- fifo命名管道
- 共享内存
- 信号量
- socket通信
管道
- 两个或多个进程间通过管道,可以互相传递信息,利用read和write系统调用函数来进行读写操作
- 管道可以看作成一个文件,有两个文件描述符,分别用来读文件和写文件,但同一时刻只能一读一写,因此又称半双工通信
- 特点是:仅适用于同一组先的进程间通信
接口代码
#include <unistd.h>
int pipe(int filedes[2]);
参数解释
- filedes: 一个有两个成员的整形数组,用来保存管道文件描述符
- filedes[0]: 从管道读数据
- filedes[1]: 从管道写数据
返回值
返回值非0,表示错误
- EMFILE: 进程使用的文件描述符过多
- ENFILE: 系统的文件表已满
- EFAULT: 文件描述符无效
实例代码
从管道中读文件和写文件
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int main()
{
int filedes[2];
int fd;
char *buff = "这是管道通信";
char out[100];
if (pipe(filedes) == 0)
{
fd = write(filedes[1], buff, strlen(buff));
printf("写入%d个字符\n", fd);
fd = read(filedes[0], out, strlen(buff));
printf("读取%d个字节,字符串为:%s \n", fd, out);
}
exit(0);
}
/**
* 运行结果
* 写入18个字符
* 读取18个字节,字符串为:这是管道通信
*/
子进程向管道中写数据,父进程读数据
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
int filedes[2]; // 定义管道文件描述符
pid_t pid;
int len;
char some_data[1024]; // 输入缓冲区
char buff[1024]; // 输出缓冲区
strcpy(some_data, argv[1]);
if (pipe(filedes) == 0)
{
pid = fork();
if (pid < 0)
printf("子进程创建失败\n");
else if (pid == 0)
{
close(filedes[0]);
len = write(filedes[1], some_data, strlen(argv[1]));
printf("写入: %d个字节,写入字符串为: %s\n", len, argv[1]);
}
else
{
wait(NULL);
close(filedes[1]);
len = read(filedes[0], buff, 1024);
printf("从管道中读取: %d个字节,字符串为: %s\n", len, buff);
}
}
exit(0);
}
/**
* 输出结果为
* 写入: 30个字节,写入字符串为: 我是牢弟,嗨,牢大,肘击
* 从管道中读取: 30个字节,字符串为: 我是牢弟,嗨,牢大,肘击
*/
命名管道
- 命名管道不需要程序有一个共同祖先进程启动
- 命名管道是一种特殊类型的文件,行为和管道类似
接口代码
以命令行的方式创建FIFO管道
mknod filename p
mkfifo filename p
程序中创建FIFO管道
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char* filename,mode_t mode);
int mknod(const char* filename,mode_t mode|S_IFIFP,(dev_t)0);
参数解释
- filename: 要创建的文件名
- mode: 文件的权限
- (dev_t)0: 无实际意义,通常设置为0
返回值
- 成功时返回 0。
- 失败时返回 -1,并设置
errno
以指示错误原因。
实例代码
mkfifo文件
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int res = mkfifo("./mkfifo", 0777); // 创建管道文件
if (res == 0)
printf("命名管道创建成功\n");
else
perror("创建失败\n");
exit(0);
}
mkfileRead文件
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
int main()
{
char buff[1024] = {0};
int fd;
int len = 0;
fd = open("./mkfifo", O_RDONLY, 0); // 打开管道文件
if (fd == -1)
{
printf("文件打开失败\n");
exit(1);
}
else
{
if ((len = read(fd, buff, 1024)) == -1) // 读取管道文件
{
printf("文件读取失败\n");
exit(1);
}
else
{
printf("文件读取成功,读取字符数为: %d,字符串为: %s\n", len, buff);
}
}
close(fd);
exit(0);
}
mkfileWrite文件
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
int main()
{
char buff[1024] = "写入:这里是mkfifoRead";
int fd;
int len = 0;
fd = open("./mkfifo", O_WRONLY, 0); // 打开管道文件
if (fd == -1)
{
printf("文件打开失败\n");
exit(1);
}
else
{
if ((len = write(fd, buff, 1024)) == -1) // 读取管道文件
{
printf("文件写入失败\n");
exit(1);
}
else
{
printf("文件写入成功,写入字符串长度为 %d,字符串为 %s\n", len, buff);
}
}
close(fd);
exit(0);
}