进程间通信
说明
无名管道(pipe)
命名管道(fifo)
内存映射(mapped memeory),
消息队列(message queue)
共享内存(shared memory)
信号量(semaphore)
信号(signal)
文件(file)
套接字(Socket)
无名管道
在具有亲缘进程间的单向管道
读写的是一个流
注意控制,流向的方法
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <iostream>
int main() {
using std::cout;
using std::endl;
using std::string;
using std::to_string;
int pipe_fd[2];
const int MAX_BUF_LENGTH = 256;
char buf[MAX_BUF_LENGTH];
string data = "Pip test program";
memset(buf,0,sizeof(buf));
if (pipe(pipe_fd) < 0) {
cout << "Pipe create error.\n";
exit(1);
}
else {
pid_t pid = fork();
if (pid == 0) {
close(pipe_fd[1]);
int real_read;
if ((real_read = read(pipe_fd[0],buf,MAX_BUF_LENGTH)) > 0) {
cout << "get = [" << real_read << "] = " << buf << "\n";
}
close(pipe_fd[0]);
return 0;
}
else if (pid > 0) {
close(pipe_fd[0]);
int real_write;
if ((real_write = write(pipe_fd[1],data.c_str(),data.size())) != -1) {
cout << "send = [" << real_write << "] = " << data << endl;
}
close(pipe_fd[1]);
wait(0);
return 0;
}
else {
cout << "Unknow pid = " << pid << endl;
}
}
return 0;
}
命名管道
FIFO(命名管道)不同于匿名管道之处在于它提供⼀个路径名与之关联,以FIFO的⽂件形式存储于⽂件系统中。命名管道是⼀个设备⽂件,因此,即使进程与创建FIFO的进程不存在亲缘关系,只要可以访问该路径,就能够通过FIFO相互通信。值得注意的是,FIFO(first input first output)总是按照先进先出的原则⼯作,第⼀个被写⼊的数据将⾸先从管道中读出。
就是创建一个可以在文件系统长寻找的设备,通过该设备进行,通信
注意设备不能重复创建,需要一定的判断,以及注意设备的权限问题
这个设备标记了内核中的一块缓冲区所以对读写没有什么限制,可以多次、多进程去写、读
read.cpp
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string>
const std::string PATH = "./fifo";
const int SIZE = 128;
int main() {
umask(0);
if (mkfifo(PATH.c_str(),0666 | S_IFIFO) == -1) {
perror ("mkefifo error");
// exit(0);
}
int fd = open(PATH.c_str(),O_RDONLY);
if (fd < 0) {
printf("open fd is error\n");
return 0;
}
else {
char Buf[SIZE];
while(1) {
ssize_t s = read(fd,Buf,sizeof(Buf));
if (s < 0) {
perror("read error");
exit(1);
}
else if (s == 0) {
printf("client quit! i shoud quit!\n");
break;
}
else {
Buf[s] = '\0';
printf("client# %s ",Buf);
fflush(stdout);
}
}
close(fd);
}
return 0;
}
write.cpp
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string>
const std::string PATH = "./fifo";
const int SIZE = 128;
int main() {
int fd = open(PATH.c_str(),O_WRONLY);
if (fd < 0) {
perror("open error");
return 0;
}
else {
char Buf[SIZE];
while(1) {
printf("please Enter#:");
fflush(stdout);
ssize_t s = read(0,Buf,sizeof(Buf));
if (s < 0) {
perror("read is failed");
return 1;
}
else if(s == 0) {
printf("read is closed!");
return 1;
}
else {
Buf[s]= '\0';
write(fd,Buf,strlen(Buf));
}
}
}
return 0;
}
内存映射
也可以用来拷贝文件
具有亲缘关系的进程之间
注意需要往文件里面写点东西,否则会出bus error
原因是mmap无法扩展空的物理页
也可以使用匿名文件,没有太大区别
#include <sys/mman.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
int main() {
int fd = open("./english.txt",O_RDWR | O_CREAT,0644);
if (fd == -1) {
perror("open = ");
return 1;
}
else {
write(fd,"1",1);
void* ptr = mmap(NULL,1024,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
if (ptr == MAP_FAILED) {
perror("mmap");
return 1;
}
else {
pid_t pid = fork();
if (pid > 0) {
const char * const data = "I'm parrent,who are you?";
memcpy(ptr,data,strlen(data) + 1);
}
else if (pid == 0) {
printf("Get data [%s]\n",static_cast<char*>(ptr));
}
munmap(ptr,1024);
}
sleep(1);
}
return 0;
}
陌生进程之间
write.cpp
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string>
int main() {
int fd = open("./english.txt",O_RDWR | O_CREAT,0644);
write(fd,"1",1);
void* ptr = mmap(NULL,4000,PROT_READ | PROT_WRITE,
MAP_SHARED,fd,0);
if (ptr == MAP_FAILED) {
perror("mmap");
return 0;
}
else {
const std::string str = "Hi,I'm parrent.";
memcpy(ptr,str.c_str(),str.size() + 1);
munmap(ptr,4000);
}
return 0;
}
read.cpp
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string>
int main() {
int fd = open("./english.txt",O_RDWR);
void* ptr = mmap(NULL,4000,PROT_READ | PROT_WRITE,
MAP_SHARED,fd,0);
if (ptr == MAP_FAILED) {
perror("mmap");
return 0;
}
else {
printf("[%s]\n",static_cast<char*>(ptr));
munmap(ptr,4000);
}
return 0;
}
消息队列
共享内存
信号量集
信号量集其实就是一个计数器数组,只能控制进程数量而不能互发数据。
key_t key = 8888;这里也可以同ftok(path,id)生成,大概 = id + hash(path)
g++ -oa a.cpp sem.cpp
g++ -ob b.cpp sem.cpp
./a & ./b
printf "\n"
sleep 5
sem.h
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/sem.h>
union semun {
int val;
};
void sem_init();
void sem_p();
void sem_v();
void sem_destroy();
sem.cpp
#include "sem.h"
static int semid = -1;
void sem_init() {
key_t key = 8888;
semid = semget(key,1,IPC_CREAT | IPC_EXCL | 0600 );
if (semid == -1) {
semid = semget(key,1,IPC_CREAT);
if (semid == -1) {
perror("semget create error");
return;
}
}
else {
union semun tmp;
tmp.val = 1;
if (semctl(semid,0,SETVAL,tmp) == -1) {
perror("semctl初始化失败");
return;
}
}
}
void sem_p() {
sembuf buf;
buf.sem_num = 0;
buf.sem_op = -1;
buf.sem_flg = SEM_UNDO;
if (semop(semid,&buf,1) == -1) {
perror("semop error");
return;
}
}
void sem_v() {
sembuf buf;
buf.sem_num = 0;
buf.sem_op = 1;
buf.sem_flg = SEM_UNDO;
if (semop(semid,&buf,1) == -1) {
perror("semop error");
return;
}
}
void sem_destroy() {
if (semctl(semid,0,IPC_RMID) == -1) {
perror("destory error");
}
}
a.cpp
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include "sem.h"
int main() {
sem_init();
for (int i = 0;i < 3;++i) {
sem_p();
write(1,"a",1);
sleep(rand() % 3);
write(1,"a",1);
sem_v();
sleep(rand() % 3);
}
sem_destroy();
return 0;
}
b.cpp
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include "sem.h"
int main() {
sem_init();
for (int i = 0;i < 3;++i) {
sem_p();
write(1,"b",1);
sleep(rand() % 3);
write(1,"b",1);
sem_v();
sleep(rand() % 3);
}
return 0;
}
信号
本文来自博客园,作者:XDU18清欢,转载请注明原文链接:https://www.cnblogs.com/XDU-mzb/p/16342637.html