一、进程
1.1 进程间通信的概念
线程通信通过全局变量即可。
进程间通信是相互独立的,但是所有进程都共用一份内核空间,所以进程和进程之间的通信可以通过内核去进行。
1.2 进程间通信方式
共7种:
- 传统的进程间通信方式:
- 无名管道
- 有名管道
- 信号
- systemV版本的IPC进程间通信:
- 消息队列
- 共享内存
- 信号灯集
- BSD版本的:
- socket实现本地通信
1.3 无名管道
1.3.1 无名管道的概念和特性
无名管道在内核中开辟一块内存空间,用于进程间的通信。
无名管道创建之后,回想用户返回两个文件描述符,一个读端文件描述符,一个写端文件描述符。读端文件描述符,用于从管道中读取数据,写端文件描述符,用于向管道中写入数据。
无名管道只能用于亲缘间进程的通信。
无名管道大小是64K。
1.3.2 无名管道的API
cpp
#include <unistd.h>
int pipe(int pipedf[2]);
功能:创建一个无名管道
参数:
pipefd:保存内核返回的管道的两端
pipedf[0]:管道的读端
pipedf[1]:管道的写端
返回值:成功返回0,失败返回-1,置位错误码
1.3.3 无名管道运行实例:
cpp
#include <my_head.h>
int main(int argc,const char *argv[]){
int ret = 0;
int pipedf[2] = {0};
//创建无名管道
ret = pipe(pipedf);
if(-1 == ret){
PRINT_ERR("create pipe error");
}
//创建子进程
ret = fork();
if(-1 == ret){
PRINT_ERR("fork error");
}
else if(0 == ret){
//子进程,关闭读
char send_buf[128] = {0};
close(pipedf[0]);
while(1){
fgets(send_buf,sizeof(send_buf),stdin);
send_buf[strlen(send_buf)-1] = '\0';
write(pipedf[1],send_buf,strlen(send_buf));
if(!strcmp(send_buf,"quit"))
break;
}
close(pipedf[1]);
}else{
//父进程,关闭写
char recv_buf[128] = {0};
close(pipedf[1]);
while(1){
memset(recv_buf,0,sizeof(recv_buf));
read(pipedf[0],recv_buf,sizeof(recv_buf));
if(!strcmp(recv_buf,"quit"))
break;
printf("我是父进程,我收到了数据[%s]\n",recv_buf);
}
close(pipedf[0]);
wait(NULL);
}
return 0;
}
运行结果:
无名管道的读写特点:
如果读端关闭,向管道写数据:
管道破裂,祥管道写入数据的进程会收到管道破裂的信号,这个信号会杀死该进程。
如果独断打开(不读),一直写:
有多少写多少,管道满了之后(管道大小是164K),会在write的地方阻塞
如果写端不存在,读数据:
如果管道中有数据,就读数据,如果没有数据就立即返回。
如果写端存在(不写),读数据,有数据就读数据,没数据就在read的地方阻塞
1.4有名管道
1.4.1 有名管道的特点
有名管道在内核中开辟一块内存空间,用于进程间的通信。
有名管道创建之后,会在文件系统中创建一个管道文件。
两个进程想要进行通信的时候,可以通过open函数1打开管道文件,然后向管道中写入内容,或者读取内容,实现进程间的通信。
这个管道文件本质上是保存在内存上的。
有名管道可以用于任意进程间通信。
有名管道大小为64K。
2.4.2 创建有名管道的API
cpp
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname,mode_t mode);
功能:创建一个有名管道
参数:
pathname:管道文件的路径和名字
mode:创建文件的权限(mode & ~umask)
返回值:成功返回0,失败返回-1,置位错误码
mkfifo 管道文件名 --- 通过命令创建一个有名管道
1.4.3 有名管道使用示例
mkfifo.c
cpp
#include <my_head.h>
int main(int argc,const char *argv[]){
mkfifo("./fifo",0666);
getchar();
//system("rm fifo");
remove("./fifo");//删除文件
return 0;
}
read.c
cpp
#include <my_head.h>
int main(int argc,const char *argv[]){
int fd = 0;
//1.打开管道文件,以只读的方式打开
fd = open("./fifo",O_RDONLY);
if(-1 == fd){
PRINT_ERR("open fifo error");
}
char recv_buf[128] = {0};
//2.开始循环读
while(1){
memset(recv_buf,0,sizeof(recv_buf));
read(fd,recv_buf,sizeof(recv_buf));
if(!strcmp(recv_buf,"quit"))
break;
printf("读到了数据[%s]\n",recv_buf);
}
close(fd);
return 0;
}
write.c
cpp
#include <my_head.h>
int main(int argc,const char *argv[]){
int fd = 0;
//1.以只读方式打开管道文件
fd = open("./fifo",O_WRONLY);
if(-1 == fd){
PRINT_ERR("open fifo error");
}
char send_buf[128] = {0};
//2.开始循环写
while(1){
fgets(send_buf,sizeof(send_buf),stdin);
send_buf[strlen(send_buf) - 1] = '\0';
write(fd,send_buf,strlen(send_buf));
if(!strcmp(send_buf,"quit"))
break;
}
close(fd);
return 0;
}
有名管道的读写特点:
如果读端没有打开,写管道:
在open的位置阻塞。
如果读端打开(不读),写管道:
有多少写多少,写满为止,写阻塞。
读端打开后关闭,写管道:
管道破裂,向写管道的进程发送管道破裂信号,杀死该进程。
如果写端没打开,读管道:
在open的位置阻塞。
写端打开(不写),读管道:
有数据就读数据,没数据,在read的地方阻塞。
写端打开后关闭,读管道:
有数据就读数据,没数据就立即返回。