【从零开始的嵌入式生活】并发程序设计3——进程间通信(1)

简介: 【从零开始的嵌入式生活】并发程序设计3——进程间通信(1)

这一个部分是并发编程的最后一个部分,这部分因为我之前项目由接触到所以过的比较快,还有一个原因是我不太重视这些板块,所以等我以后接触多了回来补坑吧,希望大家不嫌弃我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信号机制进行了扩展,进程对信号有不同的响应方式,主要有三种方式


缺省方式

忽略信号

捕捉信号

常见的信号

9450530c301f00b951356d50532e779.png

可以使用使用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到达之后程序直接退出!



相关文章
|
4月前
|
安全 Python
告别低效编程!Python线程与进程并发技术详解,让你的代码飞起来!
【7月更文挑战第9天】Python并发编程提升效率:**理解并发与并行,线程借助`threading`模块处理IO密集型任务,受限于GIL;进程用`multiprocessing`实现并行,绕过GIL限制。示例展示线程和进程创建及同步。选择合适模型,注意线程安全,利用多核,优化性能,实现高效并发编程。
74 3
|
4月前
|
Python
解锁Python并发新世界:线程与进程的并行艺术,让你的应用性能翻倍!
【7月更文挑战第9天】并发编程**是同时执行多个任务的技术,提升程序效率。Python的**threading**模块支持多线程,适合IO密集型任务,但受GIL限制。**multiprocessing**模块允许多进程并行,绕过GIL,适用于CPU密集型任务。例如,计算平方和,多线程版本使用`threading`分割工作并同步结果;多进程版本利用`multiprocessing.Pool`分块计算再合并。正确选择能优化应用性能。
36 1
|
2月前
|
网络协议 C语言
C语言 网络编程(十三)并发的TCP服务端-以进程完成功能
这段代码实现了一个基于TCP协议的多进程并发服务端和客户端程序。服务端通过创建子进程来处理多个客户端连接,解决了粘包问题,并支持不定长数据传输。客户端则循环发送数据并接收服务端回传的信息,同样处理了粘包问题。程序通过自定义的数据长度前缀确保了数据的完整性和准确性。
|
3月前
|
算法 Java
JUC(1)线程和进程、并发和并行、线程的状态、lock锁、生产者和消费者问题
该博客文章综合介绍了Java并发编程的基础知识,包括线程与进程的区别、并发与并行的概念、线程的生命周期状态、`sleep`与`wait`方法的差异、`Lock`接口及其实现类与`synchronized`关键字的对比,以及生产者和消费者问题的解决方案和使用`Condition`对象替代`synchronized`关键字的方法。
JUC(1)线程和进程、并发和并行、线程的状态、lock锁、生产者和消费者问题
|
2月前
|
C语言
C语言 网络编程(八)并发的UDP服务端 以进程完成功能
这段代码展示了如何使用多进程处理 UDP 客户端和服务端通信。客户端通过发送登录请求与服务端建立连接,并与服务端新建的子进程进行数据交换。服务端则负责接收请求,验证登录信息,并创建子进程处理客户端的具体请求。子进程会创建一个新的套接字与客户端通信,实现数据收发功能。此方案有效利用了多进程的优势,提高了系统的并发处理能力。
|
2月前
|
数据采集 消息中间件 并行计算
进程、线程与协程:并发执行的三种重要概念与应用
进程、线程与协程:并发执行的三种重要概念与应用
59 0
|
3月前
|
存储 缓存 NoSQL
进程内缓存助你提高并发能力!
进程内缓存助你提高并发能力!
|
4月前
|
数据库 数据安全/隐私保护 C++
Python并发编程实战:线程(threading)VS进程(multiprocessing),谁才是并发之王?
【7月更文挑战第10天】Python并发对比:线程轻量级,适合I/O密集型任务,但受GIL限制;进程绕过GIL,擅CPU密集型,但通信成本高。选择取决于应用场景,线程利于数据共享,进程利于多核利用。并发无“王者”,灵活运用方为上策。
56 2
|
4月前
|
大数据 API 数据处理
Python高手都在用的并发秘籍:解锁线程与进程的终极奥义,性能飙升不是梦!
【7月更文挑战第8天】Python并发编程提升性能,线程(threading)适合I/O密集型任务,如网络请求,通过`start()`和`join()`实现并发。进程(multiprocessing)利用多核CPU,适用于CPU密集型任务,如大数据处理。结合两者可优化混合任务,实现最佳并发效果。
34 1
|
4月前
|
消息中间件 算法 Java
(十四)深入并发之线程、进程、纤程、协程、管程与死锁、活锁、锁饥饿详解
本文深入探讨了并发编程的关键概念和技术挑战。首先介绍了进程、线程、纤程、协程、管程等概念,强调了这些概念是如何随多核时代的到来而演变的,以满足高性能计算的需求。随后,文章详细解释了死锁、活锁与锁饥饿等问题,通过生动的例子帮助理解这些现象,并提供了预防和解决这些问题的方法。最后,通过一个具体的死锁示例代码展示了如何在实践中遇到并发问题,并提供了几种常用的工具和技术来诊断和解决这些问题。本文旨在为并发编程的实践者提供一个全面的理解框架,帮助他们在开发过程中更好地处理并发问题。

热门文章

最新文章