【Linux之进程间通信】
项目代码获取:https://gitee.com/chenshao777/linux-processes.git
(麻烦点个免费的Star哦,您的Star就是我的写作动力!)
02.无名管道
无名管道常用于有亲缘关系的进程通信,即父子进程之间的通信
int pipe(int pipefd[2]);
需要包含头文件
#include <unistd.h>
数组pipefd用于返回两个引用管道末端的文件描述符
pipefd[0]指的是管道的读取端
pipefd[1]指的是管道的写入端
创建成功返回0,失败返回-1
使用实例1(创建无名管道):
Linux进程会默认打开三个文件描述符:
0 :标准输入 stdin
1 :标准输出 stdout
2 :标准错误 stderror
所以 读取端操作符 = 3, 写入端操作符= 4
#include <unistd.h>
#include <stdio.h>
/*
创建无名管道,默认写管道描述符为pipefd[1]=4,管道描述符为pipefd[0]=3
创建成功返回0,失败返回-1
无名管道只能实现亲缘关系进程间的通信
测试命令: ./1.out
*/
int main(int argc, char *argv[])
{
int pipefd[2];
int pipe_res;
/*创建无名管道*/
pipe_res = pipe(pipefd);
if(pipe_res == 0)
/*
Linux进程会默认打开三个文件描述符:
0 :标准输入 stdin
1 :标准输出 stdout
2 :标准错误 stderror
所以pipefd[0] = 3, pipefd[1] = 4
*/
printf("pipefd[0] = %d, pipefd[1] = %d\n",pipefd[0],pipefd[1]);
else
printf("创建无名管道失败!\n");
close(pipefd[0]);
close(pipefd[1]);
return 0;
}
使用实例2(无名管道读写操作):
读写无名管道(无名管道实际上是存在与内核空间的一个队列)
读管道是出队操作,写管道是入队操作
无名管道读数据后数据会被删除,如果没有读到数据则会堵塞
写管道写溢出后也会阻塞,写满是65536字节
测试命令: ./2.out
- 去掉 “/再次读管道,会阻塞/” 下面三行注释的运行结果:
第一次读管道成功,接着阻塞(因为读管道后会数据被删除,管道空了再读会阻塞) - 不去掉注释的运行结果:
“没有写满1” 不会打印,因为无名管道写满是65536字节,代码中写了65537个字节,溢出了,所以会阻塞
#include <unistd.h>
#include <stdio.h>
#include <string.h>
/*
读写无名管道(无名管道实际上是存在与内核空间的一个队列)
读管道是出队操作,写管道是入队操作
无名管道读数据后数据会被删除,如果没有读到数据则会堵塞
写管道写溢出后也会阻塞,写满是65536字节
测试命令: ./2.out
结果: 第一次读管道成功,接着阻塞
*/
int main(int argc, char *argv[])
{
int pipefd[2];
int pipe_res;
char write_buff[100] = "123451234512345"; //15个字节
char read_buff[100] = {0};
/*创建无名管道*/
pipe_res = pipe(pipefd);
if(pipe_res == 0)
/*
Linux进程会默认打开三个文件描述符:
0 :标准输入 stdin
1 :标准输出 stdout
2 :标准错误 stderror
所以pipefd[0] = 3, pipefd[1] = 4
*/
printf("pipefd[0] = %d, pipefd[1] = %d\n",pipefd[0],pipefd[1]);
else{
printf("创建无名管道失败!\n");
return -1;
}
/*写管道*/
write(pipefd[1], write_buff, strlen(write_buff));
/*读管道*/
read(pipefd[0], read_buff, 100);
printf("读管道数据1 = %s\n", read_buff);
/*再次读管道,会阻塞*/
// memset(read_buff, 0 ,sizeof(read_buff));
// read(pipefd[0], read_buff, 100);
// printf("读管道数据2 = %s\n", read_buff);
char data = 1;
for(long int i = 0; i < 65537; i++){
write(pipefd[1], &data, 1);
}
printf("没有写满1\n");
close(pipefd[0]);
close(pipefd[1]);
return 0;
}
使用实例3(主进程先运行,子进程后运行):
核心就是子进程读无名管道,父进程写无名管道
子进程读出数据判断后才能运行,没读到数据则一直阻塞,直到父进程写管道
#include <unistd.h>
#include <stdio.h>
#include <string.h>
/*
通过无名管道使父进程先运行,子进程后运行
测试命令: ./3.out
结果: 第一次读管道成功,接着阻塞
*/
int main(int argc, char *argv[])
{
int pipefd[2];
int pipe_res;
char pipe_value;
/*创建无名管道*/
pipe_res = pipe(pipefd);
if(pipe_res == 0)
printf("pipefd[0] = %d, pipefd[1] = %d\n",pipefd[0],pipefd[1]);
else{
printf("创建无名管道失败!\n");
return -1;
}
/*创建进程*/
pid_t pid_f;
pid_f = fork();
if(pid_f > 0)
{
while(1)
{
printf("我是父进程,睡眠2秒\n");
sleep(2);
printf("我是父进程\n");
printf("我是父进程\n");
printf("我是父进程\n");
/*写无名管道*/
pipe_res = 1;
write(pipefd[1], &pipe_res, 1);
sleep(1);
}
}else{
while(1)
{
/*读无名管道*/
read(pipefd[0], &pipe_res, 1);
if(pipe_res == 1){
printf("我是子进程\n");
printf("我是子进程\n");
printf("我是子进程\n");
usleep(100000);
}
}
}
close(pipefd[0]);
close(pipefd[1]);
return 0;
}