这一个部分是并发编程的最后一个部分,这部分因为我之前项目由接触到所以过的比较快,还有一个原因是我不太重视这些板块,所以等我以后接触多了回来补坑吧,希望大家不嫌弃我0.0
🧑🏻作者简介:一个学嵌入式的年轻人
✨联系方式:2201891280(QQ)
📔源码地址:https://gitee.com/xingleigao/study_qianrushi
⏳全文大约阅读时间: 60min
文章目录
无名管道
进程间通信方式
无名管道特点
无名管道创建 – pipe
无名管道的特性
读无名管道
写无名管道
思考题
有名管道
有名管道特点
有名管道创建 – mkfifo
注意:
信号机制
常见的信号
信号发送
设置信号相应方式——signal
子进程结束信号
共享内存
System V IPC
System V IPC – ftok
共享内存
使用步骤
创建 - shmget
共享内存映射 – shmat
共享内存映射 – shmat
共享内存控制 – shmctl
示例代码
消息队列
使用步骤
消息创建/打开 - msgget
消息发送 – msgsnd
消息接收 – msgrcv
控制消息队列 – msgctl
示例代码
信号灯
信号灯特点
使用步骤
信号灯创建/打开 – semget
信号灯初始化 – semctl
信号灯P/V操作 – semop
信号灯操作 – sembuf
使用示例
写在最后
无名管道
进程间通信方式
早期UNIX进程间通信方式
无名管道(pipe)
有名管道 (fifo)
信号(signal)
System V IPC
共享内存(share memory)
消息队列(message queue)
信号灯集(semaphore set)
套接字(socket)
无名管道特点
无名管道具有如下特点:
只能用于具有亲缘关系的进程之间的通信
单工的通信模式,具有固定的读端和写端
无名管道创建时会返回两个文件描述符,分别用于读写管道
无名管道创建 – pipe
#include <unistd.h> int pipe(int pfd[2]);
成功时返回0,失败时返回EOF
pfd 包含两个元素的整形数组,用来保存文件描述符
pfd[0]用于读管道;pfd[1]用于写管道
示例代码:
#include <unistd.h> #include <stdio.h> #include <string.h> int main(){ int pdf[2]; pid_t pid; int re; re = pipe(pdf); if(re == -1){ perror("pipe"); return -1; } pid = fork(); if(pid < 0){ perror("fork"); return -1; }else if(pid == 0){ char buf[64] = "I am child , pipe message!\n"; while(1){ write(pdf[1], buf, strlen(buf)); sleep(1); } }else{ char buf[64]; memset(buf, 0, sizeof(buf)); while(1){ re = read(pdf[0], buf, sizeof(buf)); if(re > 0){ printf("msg form child : %s\n",buf); } else break; } } return 0; }
无名管道的特性
读无名管道
写端存在
有数据(读数据)
无数据(阻塞)
写端不存在
有数据(不存在)
无数据(立即返回)
写无名管道
读端存在
有空间(写数据)
无空间 (阻塞)
读端不存在
有空间(不存在)
无空间(管道破裂)
思考题
如何获取管道的大小?
思路:
循环写入管道,直到阻塞
统计循环次数
#include <unistd.h> #include <stdio.h> #include <string.h> int main(){ int pdf[2]; pid_t pid; int re; int i; re = pipe(pdf); if(re == -1){ perror("pipe"); return -1; } for(i = 0;i < 10000000; ++i){ write(pdf[1], "a", 1); printf("%d\n",i); } return 0; }
有名管道
有名管道特点
对应管道文件,可用于任意进程之间进行通信
打开管道时可指定读写方式
通过文件IO操作,内容存放在内存中
有名管道创建 – mkfifo
include <unistd.h> #include <fcntl.h> int mkfifo(const char *path, mode_t mode);
成功时返回0,失败时返回EOF
path 创建的管道文件路径
mode 管道文件的权限,如0666
写程序:
#include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <string.h> int main(){ int re; int fd; char buf[32]; unlink("./myfifo"); re = mkfifo("./myfifo", 0666); if(re == -1){ perror("mkfifo"); return -1; } fd = open("./myfifo", O_WRONLY); if(fd < 0){ perror("open"); return -1; } strcpy(buf, "fifo write test"); while(1){ write(fd, buf, strlen(buf)); sleep(1); } return 0; }
读程序:
int main(){ int re; int fd; char buf[32]; fd = open("./myfifo", O_RDONLY); if(fd < 0){ perror("open"); return -1; } while(1){ memset(buf, 0, sizeof(buf)); read(fd, buf, sizeof(buf)); printf("%s\n",buf); sleep(1); } return 0; }
注意:
两个程序必须同时执行才能执行读写,否则会进行阻塞!!!
信号机制
信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式,linux内核通过信号通知用户进程,不同的信号类型代表不同的事件,Linux对早期的unix信号机制进行了扩展,进程对信号有不同的响应方式,主要有三种方式
缺省方式
忽略信号
捕捉信号
常见的信号
可以使用使用kill -l查看所有的信号
信号发送
kill/raise发送信号
#include <unistd.h> #include <signal.h> int kill(pid_t pid, int sig); int raise(int sig); //给自己发信号
成功时返回0,失败时返回EOF
pid 接收进程的进程号:
0代表同组进程; -1代表所有进程(慎用)
sig 信号类型
alarm/pause
int alarm(unsigned int seconds);
成功时返回上个定时器的剩余时间,失败时返回EOF
seconds 定时器的时间
一个进程中只能设定一个定时器,时间到时产生SIGALRM
int pause(void);
进程一直阻塞,直到被信号中断
被信号中断后返回-1,errno为EINTR
示例代码
#include <unistd.h> #include <stdio.h> #include <stdlib.h> int main(){ alarm(3); pause(); printf("I have been waken up!\n"); return 0; }
注意的是printf永远不会被执行,因为alarm到达之后程序直接退出!