1 进程通信
进程间通信(IPC)是一组编程接口,让程序员能够协调不同的进程,使之能在一个操作系统里同时运行,并相互传递、交换信息。这使得一个程序能够在同一时间里处理许多用户的要求。
用户角度: 进程是程序的一次动态执行过程
操作系统: 进程是操作系统分配资源的基本单位,也是最小单位。每一个进程占有自己独立的资源,且不能进程间直接访问各自资源。但实际情况下,进程间是需要通信的。
1.1 目的
-
进程间数据传输:不同qq用户间通信
-
通知事件:子进程结束时需要告知父进程
-
资源共享:多个进程共享同样资源,需要互斥与同步机制
-
进程控制:GDB调试
1.2 方式
-
管道通信:无名管道、有名管道
-
消息队列:
-
信号:
-
信号量:
-
共享内存:
-
套接字(socket):
2 具体介绍
2.1 无名管道:
半双工通信方式,数据只能单向传输。只能用于具有亲缘关系的进程通信。管道实际上是位于进程内核空间维护的一段缓冲器。(前面介绍过每个进程4G空间,分内核与用户区)
管道操作类似文件操作,都是基于文件描述符,进程对于文件操作符是共享的。无名管道没有文件实体,有名管道具有文件实体。消息以字节流传输,先进先出模式。
# shell 管道标志 |
ls | wc -l
# 存在两个进程,ls与wc
测试程序:
#include<iostream>
#include <unistd.h>
#include <string.h>
/*
#include <unistd.h>
struct fd_pair {
long fd[2];
};
struct fd_pair pipe();
int pipe(int pipefd[2]);
功能:创建管道,用于进程通信。
参数:传出参数:pipefd[0]--读端,pipefd[1]--写端
返回值:0-成功,-1-失败
*/
using namespace std;
// 子进程发消息,父进程接受
int main(){
int pipefd[2];
int ret = pipe(pipefd);
// 注意:管道需要在进程前开辟
if(ret == -1){
//创建失败
perror("pipe:");
exit(0);
}
// 创建子进程
pid_t pid = fork();
if(pid > 0){
//父进程
cout<<"I am Father:"<<endl;
//读数据
close(pipefd[1]);//关闭写端
char buf[1024]={0};
int len = read(pipefd[0], buf, sizeof(buf));
cout<<"Father: The Message is:"<<buf<<endl;
/*while(1){
cout<<"The Message:"<<buf<<endl;
}*/
}else if(pid == 0){
//sleep(10);
//子进程
cout<<"I am child:"<<endl;
//写数据
close(pipefd[0]);//关闭读端
char *str = "I miss you!, my Dad";
write(pipefd[1],str, strlen(str));
}
return 0;
}
2.2 有名管道(FIFO):
半双工通信方式,数据只能单向传输。文件内容存放在内核内存中,允许无亲缘关系进程间的通信。
测试: A,B聊天
#include<iostream>
#include <unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include <fcntl.h>
#include <string.h>
using namespace std;
// 进程A
int main(int argc, char){
// 1 创建管道1,2
int ret = access("fifo_1",F_OK);
if(ret == -1){
cout<<"fifo_1不存在,创建有名管道1:"<<endl;
ret = mkfifo("fifo_1",0664);
if(ret == -1){
perror("mkfifo:");
exit(0);
}
}
int ret1 = access("fifo_2",F_OK);
if(ret1 == -1){
cout<<"fifo_2不存在,创建有名管道2:"<<endl;
ret1 = mkfifo("fifo_2",0664);
if(ret1 == -1){
perror("mkfifo:");
exit(0);
}
}
// 2 只写打开1,只读打开2
int fdw = open("fifo_1",O_WRONLY);
if(fdw == -1){
perror("open:");
exit(0);
}
cout<<"A-fifo_1: 等待写入:"<<endl;
int fdr = open("fifo_2",O_RDONLY);
if(fdr == -1){
perror("open:");
exit(0);
}
cout<<"A-fifo_2: 等待读取:"<<endl;
// 3 循环写读数据
char buf[128];
while(1){
#include<iostream>
#include <unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include <fcntl.h>
#include <string.h>
using namespace std;
int main(int argc, char){
// 1 创建管道1,2
int ret = access("fifo_1",F_OK);
if(ret == -1){
cout<<"fifo_1不存在,创建有名管道1:"<<endl;
ret = mkfifo("fifo_1",0664);
if(ret == -1){
perror("mkfifo:");
exit(0);
}
}
int ret1 = access("fifo_2",F_OK);
if(ret1 == -1){
cout<<"fifo_2不存在,创建有名管道2:"<<endl;
ret1 = mkfifo("fifo_2",0664);
if(ret1 == -1){
perror("mkfifo:");
exit(0);
}
}
// 2 只写打开1,只读打开2
int fdw = open("fifo_1",O_WRONLY);
if(fdw == -1){
perror("open:");
exit(0);
}
cout<<"A-fifo_1: 等待写入:"<<endl;
int fdr = open("fifo_2",O_RDONLY);
if(fdr == -1){
perror("open:");
exit(0);
}
c#include<iostream>
#include <unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include <fcntl.h>
#include <string.h>
using namespace std;
int main(int argc, char){
// 1 创建管道1,2
int ret = access("fifo_1",F_OK);
if(ret == -1){
cout<<"fifo_1不存在,创建有名管道1:"<<endl;
ret = mkfifo("fifo_1",0664);
if(ret == -1){
perror("mkfifo:");
exit(0);
}
}
int ret1 = access("fifo_2",F_OK);
if(ret1 == -1){
cout<<"fifo_2不存在,创建有名管道2:"<<endl;
ret1 = mkfifo("fifo_2",0664);
if(ret1 == -1){
perror("mkfifo:");
exit(0);
}
}
// 2 只读打开1,只写打开2
int fdr = open("fifo_1",O_RDONLY);
if(fdr == -1){
perror("open:");
exit(0);
}
cout<<"B-fifo_1: 等待读取:"<<endl;
int fdw = open("fifo_2",O_WRONLY);
if(fdw == -1){
perror("open:");
exit(0);
}
cout<<"B-fifo_2: 等待写入:"<<endl;
// 3 循环读写数据
char buf[128];
while(1){
//read
memset(buf,0,128);
ret = read(fdr,buf,128);
if(ret <= 0){
perror("read:");
exit(0);
}
cout<<"A: "<<buf<<endl;
//write
cout<<"请发消息给A:"<<endl;
memset(buf,0,128);
fgets(buf,128,stdin);
ret = write(fdw, buf,strlen(buf));
if(ret == -1){
perror("write:");
exit(0);
}
}
close(fdw);
close(fdr);
return 0;
}out<<"A-fifo_2: 等待读取:"<<endl;
// 3 循环写读数据
char buf[128];
while(1){
//write
cout<<"请发消息给B:"<<endl;
memset(buf,0,128);
fgets(buf,128,stdin);
ret = write(fdw,buf,strlen(buf));
if(ret == -1){
perror("write:");
exit(0);
}
//read
memset(buf,0,128);
ret = read(fdr,buf,128);
if(ret <= 0){
perror("read:");
exit(0);
}
cout<<"B: "<<buf<<endl;
}
close(fdw);
close(fdr);
return 0;
}//write
cout<<"请发消息给B:"<<endl;
memset(buf,0,128);
fgets(buf,128,stdin);
ret = write(fdw,buf,strlen(buf));
if(ret == -1){
perror("write:");
exit(0);
}
//read
memset(buf,0,128);
ret = read(fdr,buf,128);
if(ret <= 0){
perror("read:");
exit(0);
}
cout<<"B: "<<buf<<endl;
}
close(fdw);
close(fdr);
return 0;
}
//*******************************************
#include<iostream>
#include <unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include <fcntl.h>
#include <string.h>
using namespace std;
//进程B
int main(int argc, char){
// 1 创建管道1,2
int ret = access("fifo_1",F_OK);
if(ret == -1){
cout<<"fifo_1不存在,创建有名管道1:"<<endl;
ret = mkfifo("fifo_1",0664);
if(ret == -1){
perror("mkfifo:");
exit(0);
}
}
int ret1 = access("fifo_2",F_OK);
if(ret1 == -1){
cout<<"fifo_2不存在,创建有名管道2:"<<endl;
ret1 = mkfifo("fifo_2",0664);
#include<iostream>
#include <unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include <fcntl.h>
#include <string.h>
using namespace std;
int main(int argc, char){
// 1 创建管道1,2
int ret = access("fifo_1",F_OK);
if(ret == -1){
cout<<"fifo_1不存在,创建有名管道1:"<<endl;
ret = mkfifo("fifo_1",0664);
if(ret == -1){
perror("mkfifo:");
exit(0);
}
}
int ret1 = access("fifo_2",F_OK);
if(ret1 == -1){
cout<<"fifo_2不存在,创建有名管道2:"<<endl;
ret1 = mkfifo("fifo_2",0664);
if(ret1 == -1){
perror("mkfifo:");
exit(0);
}
}
// 2 只读打开1,只写打开2
int fdr = open("fifo_1",O_RDONLY);
if(fdr == -1){
perror("open:");
exit(0);
}
cout<<"B-fifo_1: 等待读取:"<<endl;
int fdw = open("fifo_2",O_WRONLY);
if(fdw == -1){
perror("open:");
exit(0);
}
cout<<"B-fifo_2: 等待写入:"<<endl;
// 3 循环读写数据
char buf[128];
while(1){
//read
memset(buf,0,128);
ret = read(fdr,buf,128);
if(ret <= 0){
perror("read:");
exit(0);
}
cout<<"A: "<<buf<<endl;
//write
cout<<"请发消息给A:"<<endl;
memset(buf,0,128);
fgets(buf,128,stdin);
ret = write(fdw, buf,strlen(buf));
if(ret == -1){
perror("write:");
exit(0);
}
}
close(fdw);
close(fdr);
return 0;
} if(ret1 == -1){
perror("mkfifo:");
exit(0);
}
}
// 2 只读打开1,只写打开2
int fdr = open("fifo_1",O_RDONLY);
if(fdr == -1){
perror("open:");
exit(0);
}
cout<<"B-fifo_1: 等待读取:"<<endl;
int fdw = open("fifo_2",O_WRONLY);
if(fdw == -1){
perror("open:");
exit(0);
}
cout<<"B-fifo_2: 等待写入:"<<endl;
// 3 循环读写数据
char buf[128];
while(1){
//read
memset(buf,0,128);
ret = read(fdr,buf,128);
if(ret <= 0){
perror("read:");
exit(0);
}
cout<<"A: "<<buf<<endl;
//write
cout<<"请发消息给A:"<<endl;
memset(buf,0,128);
fgets(buf,128,stdin);
ret = write(fdw, buf,strlen(buf));
if(ret == -1){
#include<iostream>
#include <unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include <fcntl.h>
#include <string.h>
using namespace std;
int main(int argc, char){
// 1 创建管道1,2
int ret = access("fifo_1",F_OK);
if(ret == -1){
cout<<"fifo_1不存在,创建有名管道1:"<<endl;
ret = mkfifo("fifo_1",0664);
if(ret == -1){
perror("mkfifo:");
exit(0);
}
}
int ret1 = access("fifo_2",F_OK);
if(ret1 == -1){
cout<<"fifo_2不存在,创建有名管道2:"<<endl;
ret1 = mkfifo("fifo_2",0664);
if(ret1 == -1){
perror("mkfifo:");
exit(0);
}
}
// 2 只读打开1,只写打开2
int fdr = open("fifo_1",O_RDONLY);
if(fdr == -1){
perror("open:");
exit(0);
}
cout<<"B-fifo_1: 等待读取:"<<endl;
int fdw = open("fifo_2",O_WRONLY);
if(fdw == -1){
perror("open:");
exit(0);
}
cout<<"B-fifo_2: 等待写入:"<<endl;
// 3 循环读写数据
char buf[128];
while(1){
//read
memset(buf,0,128);
ret = read(fdr,buf,128);
if(ret <= 0){
perror("read:");
exit(0);
}
cout<<"A: "<<buf<<endl;
//write
cout<<"请发消息给A:"<<endl;
memset(buf,0,128);
fgets(buf,128,stdin);
ret = write(fdw, buf,strlen(buf));
if(ret == -1){
perror("write:");
exit(0);
}
}
close(fdw);
close(fdr);
return 0;
} perror("write:");
exit(0);
}
}
close(fdw);
close(fdr);
return 0;
}
2.3 内存映射:
磁盘文件映射到内存(共享库),多个进程映射同一快磁盘。
测试程序:
#include <iostream>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <wait.h>
#include <string.h>
using namespace std;
int main(){
// 1 打开一个磁盘文件
int fd = open("test.txt",O_RDWR);
int size = lseek(fd,0, SEEK_END);
// 2 创建内存映射区
void *ptr = mmap(NULL,size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(ptr == MAP_FAILED){
perror("mmap:");
exit(0);
}
// 3 创建子进程
pid_t pid = fork();
if(pid > 0){
//father
wait(NULL);
strcpy((char *)ptr, "hello, my son!");
}else if(pid == 0){
//child
char buf[64];
strcpy(buf, (char *)ptr);
cout<<"the sessages: "<<buf<<endl;
}
// 关闭映射区
munmap(ptr,size);
return 0;
}
2.4 信号:
软中断,事件发生时的进程间通知机制。
测试程序:
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
using namespace std;
int main(){
pid_t pid = fork();
if(pid > 0){
//kill child processes
sleep(2);
cout<<"father: kill! "<<endl;
kill(pid, SIGINT);
}else if(pid == 0){
cout<<"child: wait to kill! "<<endl;
for(int i =0 ; i < 5; i++){
cout<<"child: "<<i<<endl;
sleep(1);
}
}
return 0;
}
其他,包括定时器,等待,不累述。
2.5 共享内存:
共享物理内存里的一块区域,比内存映射效率高。创建共享内存段后,该段成为进程用户空间一部分。可供多进程共享。
测试:
#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
using namespace std;
int main(){
//1 创建共享内存段
int shmid = shmget(100, 4096, IPC_CREAT | 0664);
// 2 关联当前进场
void *ptr = shmat(shmid, NULL, 0);
char *str = "hello world!";
// 3 写端 写数据
memcpy(ptr, str, strlen(str)+1);
// 3 读端
// 3 读数据
// cout<<"data: "<<(char *)ptr<<endl;
cout<<"输入任意键解除关联:";
getchar();
// 4 解除关联
shmdt(ptr);
// 删除共享内存
shmctl(shmid, IPC_RMID, NULL);
return 0;
}