目录
线程间的通信方式
全局变量
进程的特点
系统会为每一个进程分配0-4g的虚拟空间,0-3g(用户空间)是每个进程所独有的,3g-4g(内核空间)是所有进程共有的。
CPU调度进程时会给进程分配时间片(几毫秒~十几毫秒),当时间片用完后,cpu再进行其他进程的调度,实现进程的轮转,从而实现多任务的操作。
为什么要进程间通信,进程间通信可以做什么
1).数据传输
一个进程需要将它的数据发送给另一个进程;
2).资源共享
多个进程之间共享同样的资源;
3).通知事件
一个进程需要向另一个或一组进程发送消息,通知它们发生了某种事件;
4).进程控制
有些进程希望完全控制另一个进程的执行(如Debug进程),该控制进程希望能够拦截另一个进程的所有操作,并能够及时知道它的状态改变。
1.进程间通信方式
早期进程间通信:无名管道、有名管道、信号
system V IPC 对象:共享内存、信号灯集、消息队列
BSD:socket
2.无名管道
特点
a.无名只能用于具有亲缘关系的通信。
b.半双工通信,有固定的读端和写端。
(单工:单方向,电视、广播。
半双工:可以双向,同一时刻只能在一个方向。
全双工:可以同一时刻双向。)
c.无名管道可以看作一种特殊的文件,对于他的读写,可以使用文件IO如read、write。
d.无名管道借助文件描述符通信,当管道建立,自动创建两个文件描述符,fd[0]读管道、fd[1]写管道。
函数接口
int pipe(int fd[2])
功能:创建无名管道
参数:文件描述符 fd[0]:读端 fd[1]:写端
返回值:成功 0
失败 -1
注意事项
- 当管道中无数据时,读操作阻塞;管道中无数据,将写端关闭,读操作立即返回;
- 管道中写满64k时,写阻塞,读出4k空间,写继续;
- 只有管道的读端存在,向管道中写数据才有意义,会导致管道破裂,内核发送SIGPIPE信号。
练习
父子进程实现通信,父进程循环从终端输入数据,子进程循环打印,当输入quit结束。
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char const *argv[])
{
int fd[2] = {0};//定义两个文件描述符
char buf[32] ="";
int pfd=pipe(fd);
if (pfd < 0)//1.先创建无名管道
{
perror("pipe err");
return -1;
}
printf("fd[0]:%d fd[1]:%d\n", fd[0],fd[1]);//读端、写端
pid_t pid = fork();//2.后创建父子进程,拿到同一个管道
if(pid<0)
{
perror("pipe err");
return -1;
}
else if (pid == 0)
{
while (1)
{
read(fd[0], buf, 32);
if (!strcmp(buf, "quit"))
break;
printf("buf:%s\n", buf);
}
}
else{
while (1)
{
scanf("%s", buf);
write(fd[1], buf, 32);
if (!strcmp(buf, "quit"))
break;
}
wait(NULL);//回收所有的子进程
}
close(fd[0]);
close(fd[1]);
return 0;
}
运行结果
3.有名管道
特点
- 可以使不相干进程进行通信。
- 有名管道可以通过路径名指出,在文件系统中可见,但内容存放在内存中。
- 文件IO操作有名管道
- 遵循先进先出
- 不支持lseek()操作。
函数接口
int mkfifo(const char *filename,mode_t mode);
功能:创健有名管道
参数:filename:有名管道文件名
mode:权限
返回值:成功:0
失败:-1,并设置errno号
注意对错误的处理方式:
如果错误是file exist时,注意加判断,如:if(errno == EEXIST)
注意事项
- 只写方式,写阻塞,一直到另一个进程把读打开
- 只读方式,读阻塞,一直到另一个进程把写打开
- 可读可写,若管道中无数据,读阻塞。
4.总结
有名管道和无名管道的区别
无名管道 |
有名管道 |
|
使用场景 |
亲缘关系 |
不相关进程 |
特点 |
半双工 固定的读端和写端 被看作特殊的文件,通过文件IO进行操作 |
在文件系统中可见,数据存放在内存 文件IO操作 不支持lseek()操作,遵循先进先出 |
函数 |
pipe() 直接read、write |
mkfifo() 先open打开,在进行read、write |
读写特性 |
当无名管道无数据,读阻塞 当无名管道中写满64k,写阻塞 读端关闭,继续写数据会造成管道破裂 |
只写方式,写阻塞,直到另一个进程把读打开 只读方式,读阻塞,直到另一个进程把写打开 可读可写,管道中无数据时,读阻塞 |