【从零开始的嵌入式生活】并发程序设计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到达之后程序直接退出!



相关文章
|
6月前
|
Linux 程序员 数据安全/隐私保护
嵌入式 Linux进程间通信之信号量
嵌入式 Linux进程间通信之信号量
|
6月前
|
存储 Linux
嵌入式 Linux 的僵尸进程是什么?
嵌入式 Linux 的僵尸进程是什么?
|
6月前
|
Linux
嵌入式 Linux进程间的通信--信号
嵌入式 Linux进程间的通信--信号
|
6月前
|
消息中间件 Unix Linux
嵌入式 Linux进程之间的通信
嵌入式 Linux进程之间的通信
|
6月前
|
存储 Linux 程序员
嵌入式 Linux多进程
嵌入式 Linux多进程
|
消息中间件 Unix Linux
嵌入式Linux C进程间通信(三)——消息队列
嵌入式Linux C进程间通信(三)——消息队列
359 0
嵌入式Linux C进程间通信(三)——消息队列
|
Linux
嵌入式Linux C进程间通信(二)——管道(有名和无名)
嵌入式Linux C进程间通信(二)——管道(有名和无名)
136 0
嵌入式Linux C进程间通信(二)——管道(有名和无名)
|
消息中间件 安全 Linux
嵌入式Linux C进程间通信(一)——IPC概述和信号
嵌入式Linux C进程间通信(一)——IPC概述和信号
189 0
嵌入式Linux C进程间通信(一)——IPC概述和信号
|
消息中间件 缓存 算法
嵌入式Linux C多进程编程(五)——进程退出和进程的等待
嵌入式Linux C多进程编程(五)——进程退出和进程的等待
204 0
嵌入式Linux C多进程编程(五)——进程退出和进程的等待
|
Linux
嵌入式Linux C多进程编程(四)——进程创建
嵌入式Linux C多进程编程(四)——进程创建
286 0
嵌入式Linux C多进程编程(四)——进程创建