STM32实验及笔记 —— 🍓(012)Linux系统中的进程间通信
»
(001)HAL库LED点灯
(002)HAL库LCD帧动画
(003)HAL库FFT动态频谱
(004)HAL库FFT Speed Up
(005)HAL库认识DMA
(006)看门狗总结
(007)GPIO使用步骤
(008)CubeIDE实现USB外设*
(009)为什么C99
(010)Linux UDP广播注意事项
(011)Linux非阻塞TCP
(012)ARM架构防烧脚本
(013)OpenWrt交叉编译
(014)C99基本数据类型
(015)C99 结构体
(016)C99 枚举
(017)C99 的函数及左值右值
(018)C99 的指针*
(019)C99 只有值赋值,没有move*
(020)C99 数组及结构体中的数组存储空间
(021)C99标准函数库没有函数模板
(022)POSIX线程库pthread的同步锁*
(023)POSIX线程库pthread的多线程*
(024)C99的条件语句
(025)C99的选择语句
(026)C99的循环语句
(027)C99标准库中的计时与等待 *
(028)C语言中的高精度计算库GMP *
(029)C语言中的Web服务*
(030)C语言中的字符转码ICU*
(031)从几个方面显然C语言比C++效率高*
(032)C99中的弱函数weak
(033)MTU TCP SOCKET
(034)STM32 UART连续发送数据函数
(035)STM32 UART连续接收数据函数
(036)STM32重定向printf输出到USART的方法
(037)STM32 Normal与Circle
(038)STM32 UART传输错误标志位的清除
(039)STM32 UART传输空闲中断
(040)STM32 串口、RS232是单根线发数据
(041)STM32 RS485差分信号通信
(042)STM32 等待DMA传输完成指定的字节数
(043)STM32进入低功耗模式
(044)DMA传输完成中断需要清空TCx标志位
(045)STM32软件函数命名规范
(046)在单字节完成中断中处理Idle
(047)C99内置宏
(048)使能中断后中断服务程序才起作用
(049)STM32程序启动过程
(050)STM32热加载新的程序固件
(051)中断向量表的指定
(052)STM32程序内的地址空间
(053)STM32修改主程序存放的地方
(054)Bootloader参考
(055)Keil中的下载算法
(056)编译器优化出错点
🍓(001)关闭交换分区
🍓(002)格式化U盘为ext4并设定块大小为1k
🍓(003)获取linux版本信息及硬件架构信息
🍓(004)最新版Ubuntu加速
🍓(005)不稳定网络克隆360浏览器内核脚本
🍓(006)Ubuntu24.04无法运行firefox注意事项
🍓(007)MAC地址
🍓(008)RMII和PHY
🍓(009)Ubuntu Server防火墙配置
🍓(010)Linux主动让出CPU
🍓(011)Linux硬件概念
🍓(012)Linux系统中的进程间通信
🍓(013)Git禁止强制推送
🍓(014)Git禁止reset --hard
🍓(015)将未写入的缓存立即写入硬盘
🍓(016)拷贝pre-receive到每个git仓库的脚本
🍓(017)sshd密码输入错误禁用IP3分钟
🖥️(001)异机备份低功耗自用Git服务器搭建
🖥️(002)OpenWRT配置注意事项
🕹️(001)while(1){}让出CPU后重进
🕹️(002)FreeRTOS主要函数
🕹️(003)FreeRTOS临界区ENTER_CRITICAL
🕹️(004)FreeRTOS NULL未定义问题的解决
🕹️(005)优先级最低的ARM硬件中断PENDSV
🕹️(006)任务优先级层数配置
🕹️(007)不同优先级任务创建注意事项
🕹️(008)关闭同级任务的时间片轮转
🕹️(009)OTA技术
🕹️(010)FreeRTOS静态任务创建
🕹️(011)FreeRTOS列出任务列表
🕹️(012)FreeRTOS堆空间使用量统计
🕹️(013)FreeRTOS通过任务名获取TaskHandle
🕹️(014)FreeRTOS常用任务创建方式
🕹️(015)FreeRTOS解决优先级反转的任务死锁
🕹️(016)FreeRTOS超级中断:SVC
🕹️(017)FreeRTOS中断处理函数运行在特权级
🕹️(018)FreeRTOS SVC进入用户模式的方法
🕹️(019)FreeRTOS实现绝对时间间隔开始任务
🕹️(020)FreeRTOS低功耗通过Tickless实现
🕹️(021)FreeRTOS IdleHook
🕹️(022)FreeRTOS Hooks
🕹️(023)FreeRTOS主动让出CPU
🕹️(024)FreeRTOS信号量
🕹️(025)FreeRTOS解决优先级反转问题的方法
🕹️(026)FreeRTOS获得任务的优先级
🕹️(027)FreeRTOS设置任务的优先级
🕹️(028)FreeRTOS中函数的前缀
🕹️(029)硬件中断中不能调用FreeRTOS的函数
🕹️(030)底半操作的任务接收信号量处理数据
🕹️(031)启用无限期等待
🕹️(032)中断处理函数中调用FreeRTOS的函数
🕹️(033)对于FreeRTOS顶半与底半操作的原则
🕹️(034)STM32中的FATFS支持exFat
🕹️(035)FreeRTOS中的消息队列
🕹️(036)FreeRTOS中的定时任务
🕹️(037)默认生成代码没法ping板子的原因
🕹️(038)LwIP Tcp Server开发例程
🕹️(039)切记别用mutex
🕹️(040)MEMP与Pbuf的关系
🕹️(041)FreeRTOS连接ESP WiFi(待完成)
📟(001)CMSIS标准学习
🕹️(001)函数调用被优化
Linux系统中的进程间通信:

消息队列与信号量在Linux中都是文件描述符

1)信号量
#include <semaphore.h>
sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);

name:信号量在文件系统上的文件名;
oflag:可以为O_CREAT|O_EXCL(仅创建)、O_CREAT(创建或打开)、0(仅打开已存在);
mode:信号量的权限位,比如:0644;
value:信号量的初值,比如:1,不能大于SEM_VALUE_MAX;

int sem_close(sem_t *sem);//关闭信号量指针
int sem_unlink(const char *name);//删除此进程对信号量的引用
int sem_post(sem_t *sem);//V操作,将信号量的值+1
int sem_wait(sem_t *sem);//P操作,如果当前信号量小于等于0则阻塞,将信号量的值-1,否则直接将信号量-1
int sem_trywait(sem_t *sem);//非阻塞的sem_wait
int sem_getvalue(sem_t *sem, int *sval);//获取当前信号量的值,如果当前信号量上锁则返回0或者负值,其绝对值为信号量的值



2)POSIX消息队列操作
#include <mqueue.h>
1. 创建/打开消息队列
使用 mq_open() 来创建或打开一个消息队列。
2. 发送消息
使用 mq_send() 来将消息发送到消息队列中。
3. 接收消息
使用 mq_receive() 从消息队列中接收消息。
4. 关闭消息队列
使用 mq_close() 来关闭消息队列。
5. 删除消息队列
使用 mq_unlink() 删除消息队列(通常在所有进程不再使用队列时删除)。



3)例子(epoll实时消息传递):

实时读取数据进程:
sem_t* serious_alarm_sem = sem_open("/serious-alarm-high-water-level",O_CREAT,0644,0);  //创建信号量,初值为0
sem_t* alarm_sem = sem_open("/alarm-high-water-level",O_CREAT,0644,0);                         //创建信号量,初值为0

int epoll_fds = epoll_create(10);                                      //epoll缓冲区,可监听10个fd

struct epoll_event alarm_ev_descr;                                  //alarm事件
alarm_ev_descr.data.fd = fd;                                           //fd 即为open设备返回的句柄////////////////////////////////用于后续代码中的文件描述符的传递////////////////////////////////
alarm_ev_descr.events = EPOLLPRI;                                //或者EPOLLIN,EPOLLIN表示文件描述符(FD)可以进行读取操作;EPOLLPRI表示设备的紧急数据可读取。////////////////////////////////指定监听的事件////////////////////////////////
epoll_ctl(epoll_fds,EPOLL_CTL_ADD,fd,&alarm_ev_descr); //注册新的fd到epoll_fds中,监听fd的EPOLLPRI事件

int len=0;

struct epoll_event* events = malloc(10, sizeof(struct epoll_event));//分配容纳10个事件的存储空间
while(true){                                                                    //实时读取主循环
    int n = epoll_wait(epoll_fds,events,10,-1);                     //一直阻塞直到数据到来,-1表示一直等待;只要有未读完的数据就会直接返回
    for(int i=0;i<n;i++){                                                   //等到n个事件
        if (events[i].events & EPOLLPRI) {                            //如果当前是EPOLLPRI事件,那么做以下事情
            len=read(events[i].data.fd,buff,sizeof(buff));         //读取事件数据(每次读取最大的数据量大小与设备的缓冲区大小有关,比如TCP为8K)
            ....                                                                     //拼装数据形成设备指令
            if(level>5.1){                                                      //如果指定值大于5.1
                post_sem(serious_alarm_sem);                        //发完信号量就进入下一读取过程,以提高实时性(严重告警信号量+1)
            }else if(level>2.1){
	        post_sem(alarm_sem);                                    //发完信号量就进入下一读取过程,以提高实时性(告警信号量+1)
            }
        }
    }
										     //主循环中使用epoll后不需要使用usleep(1),不会导致CPU100%,因为epoll在设备缓冲区没有数据的时候会wait、会阻塞、会释放CPU
}


告警服务进程:
sem_t* alarm_sem=sem_open("/alarm-high-water-level",O_CREAT,0644,0);//创建信号量,初值为0
while(true){
    sem_wait(alarm_sem);
    mq_send(...);//立即响应,发送到消息队列:要求播放一次"/home/reservoir-water-level-alarm.mp3"
}

严重告警服务进程:
sem_t* serious_alarm_sem=sem_open("/serious-alarm-high-water-level",O_CREAT,0644,0);//创建信号量,初值为0
while(true){
    sem_wait(serious_alarm_sem);
    mq_send(...);//立即响应,发送到消息队列:要求播放一次"/home/reservoir-water-level-serious-alarm.mp3"
}

播放音频服务进程:
bool bIsPlaying=false;
char last_play_filename[1024]={0};
while(true){
    mq_receive(...);//接收消息队列
    if(bIsPlaying&&strcmp(play_filename, last_play_filename)==0){
        //正在播放且曲目一致,则不做任何事
    }else if(bIsPlaying&&strcmp(play_filename, last_play_filename)!=0){
        //正在播放,但曲目不一致,则立即响应为新曲目
        stop_play_thread();
        start_play_once_thread(play_filename);
    }else{
	//如果未在播放,则立即播放
        start_play_once_thread(play_filename);
    }
}
无论是sched_yield的尝试,还是对while(true){}的资源消耗的错误理解,都是为了一直想推广的、提高计算机系统实时性的去sleep化:
epoll与一般阻塞模型的比较:epoll不需要多子进程、epoll的并发更高。
epoll与select的比较:epoll会wait、不需要sleep或者usleep,epoll的实时性更高。
«
——张人杰·www.v-signon.com学习者共勉
返回上一页
备案号:京ICP备19038994号-2
个人作品网站:www.up-task.com 主办:个人 English
网站内容如有侵权,请联系删除:1307776259@qq.com