当前位置: 首页 > news >正文

【学习嵌入式-day-27-进程间通信】

线程间循环打印ABC,使用信号量决定打印顺序

#include "../head.h"sem_t sem_a;
sem_t sem_b;
sem_t sem_c;void *thread1(void *arg)
{while(1){sem_wait(&sem_a);printf("A\n");sem_post(&sem_b);}return NULL;
}
void *thread2(void *arg)
{while(1){sem_wait(&sem_b);printf("B\n");sem_post(&sem_c);}return NULL;
}
void *thread3(void *arg)
{while(1){sem_wait(&sem_c);printf("C\n");sem_post(&sem_a);}return NULL;
}int main(void)
{pthread_t tid1;pthread_t tid2;pthread_t tid3;sem_init(&sem_a, 0, 1);sem_init(&sem_b, 0, 0);sem_init(&sem_c, 0, 0);pthread_create(&tid1, NULL, thread1, NULL);pthread_create(&tid2, NULL, thread2, NULL);pthread_create(&tid3, NULL, thread3, NULL);pthread_join(tid1, NULL);pthread_join(tid2, NULL);pthread_join(tid3, NULL);sem_destroy(&sem_a);sem_destroy(&sem_b);sem_destroy(&sem_c);return 0;
}

进程间通信

概念

  • 进程空间是独立的,包含文本段、数据段和系统数据段
  • 多个进程没有共享的用户空间,进程是操作系统资源分配的最小单元
  • 只能利用内核实现进程间通信

进程间通信常用的方式

传统Unix系统中的通信方式

  • 管道
  • 信号

SYS V分支中的通信方式

  • 消息队列
  • 共享内存
  • 信号量数组(信号灯)

BSD分支中的通信方式

  • 本地域套接字

管道(内核缓存区)

分类

  • 有名管道
  • 无名管道(只能用于具有亲缘关系的进程间通信)

无名管道

  • 原理:
    • 无名管道是一段内核缓存区
    • 父进程通过Pipe创建无名管道
    • 只有该父进程的子进程才能继承文件描述符,
  • 函数接口
    • pipe :

                创建无名管道,0读,1写   

#include "../head.h"int main(void)
{int pipefd[2];int pipefd2[2];int ret = 0;pid_t pid;char tmpbuff[4096] = {0};char tmpbuff2[4096] = {0};ret = pipe(pipefd);if(-1 == ret || pipe(pipefd2) == -1){perror("fail to pipe");return -1;}pid = fork();if(-1 == pid){perror("fail to fork");return -1;}if(0 == pid)    //子进程{strcpy(tmpbuff, "hello world");write(pipefd[1], tmpbuff, strlen(tmpbuff));read(pipefd2[0], tmpbuff2, sizeof(tmpbuff2));printf("tmpbuff2 = %s\n", tmpbuff2);}else if(pid > 0)    //父进程{read(pipefd[0], tmpbuff, sizeof(tmpbuff));printf("tmpbuff = %s\n", tmpbuff);strcpy(tmpbuff2, "thank you");write(pipefd2[1], tmpbuff2, strlen(tmpbuff2));}close(pipefd[0]);close(pipefd[1]);close(pipefd2[0]);close(pipefd2[1]);return 0;
}
  • 管道操作特性
    • 管道中至少有一个写端
      • 读取数据时,如果管道中有数据,则直接读出
      • 管道中没有数据, 则阻塞等待有数据写入才能读出
    • 管道中没有写端
      • 读取数据时,管道中有数据,直接读出
      • 没有数据,不阻塞等待直接向下执行
    • 管道中至少有一个读端
      • 写入数据时,如果管道没有写满,则直接写入
      • 管道存满,则阻塞等待有数据读出,才能继续写入
    • 管道中没有读端
      • 写入数据时,会产生管道破裂的信号导致进程任务异常退出

有名管道

与无名管道区别
  • 有名管道有名字,可以通过名字找到该管道
  • 可以用于任意进程间的通信
  • 进程间通信最简单、易实现的方式

操作方式
  • 进程一使用open以 读、写、读写方式打开管道文件
  • 进程二使用open以读、写、读写方式打开管道文件
  • 两个进程可以通过向管道文件中读写数据实现进程的通信
函数接口

mkfifo

循环实现,write.c从终端写字符串,read.c从终端接收,再往终端写字符串,write接收

发一次,收一次,循环

//read.c
#include "../head.h"int main(void)
{int fdr = 0;int fdw = 0;char tmpbuff[4096] = {0};mkfifo("./myfifo1", 0777);mkfifo("./myfifo2", 0777);fdr = open("./myfifo1", O_RDONLY);//可以直接设置为只读RDWRif(-1 == fdr){perror("fail to open");return -1;}fdw = open("./myfifo2", O_WRONLY);if(-1 == fdw){perror("fail to open");return -1;}printf("管道打开成功\n");while(1){memset(tmpbuff, 0, sizeof(tmpbuff));//清零read(fdr, tmpbuff, sizeof(tmpbuff));printf("RECV:%s\n", tmpbuff);memset(tmpbuff, 0, sizeof(tmpbuff));m_fgets(tmpbuff);write(fdw, tmpbuff, strlen(tmpbuff));}close(fdr);close(fdw);return 0;
}
//wirte.c#include "../head.h"int main(void)
{int fdr = 0;int fdw = 0;char tmpbuff[4096] = {0};mkfifo("./myfifo1", 0777);mkfifo("./myfifo2", 0777);fdw = open("./myfifo1", O_WRONLY);if(-1 == fdr){perror("fail to open");return -1;}fdr = open("./myfifo2", O_RDONLY);if(-1 == fdw){perror("fail to open");return -1;}printf("管道打开成功\n");while(1){memset(tmpbuff, 0, sizeof(tmpbuff));m_fgets(tmpbuff);write(fdw, tmpbuff, strlen(tmpbuff));memset(tmpbuff, 0, sizeof(tmpbuff));read(fdr, tmpbuff, sizeof(tmpbuff));printf("RECV:%s\n", tmpbuff);}close(fdr);close(fdw);return 0;
}

信号

概念

  • linux系统中的信号,主要实现应用层和内核层之间的信号通知
  • 应用层和内核层之间通信的信号,根据含义分为很多不同的信号
  • 信号主要用于多个进程任务间的时间通知
  • 信号可以用于异步通信
  • 信号的类型
    • 使用kill-l查看信号的类型

信号的处理方式

  • 缺省:信号来了,按照默认方式处理
  • 忽略:信号来了,不处理信号,忽略信号
  • 捕捉:信号来了,按照用户自己定义的方式处理信号
  • 9号信号(SIGKILL)和19号信号(SIGSTOP),不能被忽略和捕捉的

函数接口

signal

从终端输入 ctrl + C打印打印 SIGINT信号来了
输入 ctrl + \打印 SIGQUIT信号来了
输入 ctrl + z打印 SIGTSTP信号来了

#include "../head.h"void handler1(int signo)
{printf("SIGNINT信号来了\n");
}
void handler2(int signo)
{printf("SIGQUIT信号来了\n");
}
void handler3(int signo)
{printf("SIGTSTP信号来了\n");
}
int main(void)
{void(*pret1)(int) = NULL;void(*pret2)(int) = NULL;void(*pret3)(int) = NULL;pret1 = signal(SIGINT, handler1);if(SIG_ERR == pret1){perror("fail to signal");return -1;}pret2 = signal(SIGQUIT, handler2);if(SIG_ERR == pret2){perror("fail to signal");return -1;}pret3 = signal(SIGTSTP, handler3);if(SIG_ERR == pret3){perror("fail to signal");return -1;}while(1){}return 0;
}

alarm

#include "../head.h"void handler(int signo)
{printf("SIGALRM信号来了\n");alarm(5);return;
}int main(void)
{signal(SIGALRM, handler);alarm(5);while (1){printf("正在运行...\n");sleep(1);}return 0;
}
kill

#include "../head.h"pid_t pid;void handler_parent(int signo)
{if (SIGQUIT == signo){kill(pid, SIGUSR2);}else if (SIGUSR1 == signo){printf("父进程:收到子进程发送的信号了\n");}return;
}void handler_child(int signo)
{if (SIGINT == signo){kill(getppid(), SIGUSR1);}else if (SIGUSR2 == signo){printf("子进程:收到父进程发送的信号了\n");}return;
}int main(void)
{pid = fork();if (-1 == pid){perror("fail to fork");return -1;}if (0 == pid){signal(SIGUSR2, handler_child);signal(SIGINT, handler_child);signal(SIGQUIT, SIG_IGN);}else if (pid > 0){signal(SIGUSR1, handler_parent);signal(SIGQUIT, handler_parent);signal(SIGINT, SIG_IGN);}while (1){}return 0;
}

http://www.xdnf.cn/news/1324675.html

相关文章:

  • Docker常见指令速查
  • 用户认证技术
  • STL库——string(类函数学习)
  • SQL详细语法教程(六)存储+索引
  • AI心理助手开发文档
  • 在python中等号左边的都是对象,在matlab中等号a = 3+2 a就是个变量
  • 力扣hot100:盛最多水的容器:双指针法高效求解最大容量问题(11)
  • openfeign 只有接口如何创建bean的
  • Linux设备树简介
  • vue3入门-v-model、ref和reactive讲解
  • Leetcode 16 java
  • Effective C++ 条款49:了解new-handler的行为
  • 力扣 hot100 Day77
  • 单片机驱动LCD显示模块LM6029BCW
  • 机器翻译论文阅读方法:顶会(ACL、EMNLP)论文解析技巧
  • STM32学习笔记14-I2C硬件控制
  • 大数据计算引擎(四)—— Impala
  • Fluss:颠覆Kafka的面向分析的实时流存储
  • GPT-5之后:当大模型更新不再是唯一焦点
  • 深度学习必然用到的概率知识
  • Vue 3中watch的返回值:解锁监听的隐藏技巧
  • 敏感数据加密平台设计实战:如何为你的系统打造安全“保险柜”
  • 遥感机器学习入门实战教程 | Sklearn 案例②:PCA + k-NN 分类与评估
  • Day8--滑动窗口与双指针--1004. 最大连续1的个数 III,1658. 将 x 减到 0 的最小操作数,3641. 最长半重复子数组
  • 具身智能2硬件架构(人形机器人)摘自Openloong社区
  • Next.js 中的 SEO:搜索引擎优化最佳实践
  • flutter项目适配鸿蒙
  • JMeter与大模型融合应用之构建AI智能体:评审性能测试脚本
  • 【Jenkins】03 - 自动构建和docker构建
  • MCP协议演进:从SSE到Streamable HTTP的技术革命