Linux软件编程(8)—进程间通信(2)消息队列、共享内存、信号灯

一、消息队列

1. IPC对象:

IPC对象可以理解为一种内存文件

IPC对象在操作系统关闭的情况下数据被回收掉

IPC对象可以通过文件系统来定位

每个IPC对象可以创建一个消息队列、一个共享内存、一个信号

2. IPC对象操作命令:

(1)查看IPC对象

        ipcs 

        ipcs -q/m/s 查看消息队列/共享内存/信号灯

(2)删除IPC对象

        ipcrm

        ipcrm -q/m/s 消息队列/共享内存/信号灯的ID

        ipcrm -Q/M/S IPC对象的Key值

(3)操作流程

        创建/打开消息队列

        向消息队列中发送消息

        从消息队列中接收消息

(4)函数接口

①ftok

原型:key_t ftok(const char *pathname, int proj_id);
功能:
根据pathname和proj_id生成IPC对象名称
参数:
pathname:路径
proj_id:项目ID(8位)
返回值:
成功返回创建的IPC对象的名称
失败返回-1

②msgget

原型:int msgget(key_t key, int msgflg);
功能:
根据key值创建消息队列
参数:
key:IPC对象的名称
msgflg:创建标志
IPC_CREAT 不存在创建
IPC_EXCL 存在报错
返回值:
成功返回消息队列ID
失败返回-1

③msgsnd

原型:int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
功能:
向消息队列中发送消息
参数:
msqid:消息队列的ID号
msgp:发送消息内容空间的首地址
msgsz:发送消息内容的大小
msgflg:发送消息的标志
返回值:
成功返回0
失败返回-1

④msgrcv

原型:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
功能:
从消息队列中接收消息
参数:
msgqid:消息队列的ID号
msgp:存放消息空间的首地址
msgsz:最多接收消息的大小
msgtyp:接收消息的类型
返回值:
成功返回实际拷贝到空间的字节数
失败返回-1

⑤msgctl

原型:int msgctl(int msqid, int cmd, struct msqid_ds *buf);
功能:
删除消息队列
参数:
msqid:消息队列的ID号
cmd:IPC_RMID 删除类型
buf:默认为NULL
返回值:
成功返回0
失败返回-1

#include "../head.h"

typedef struct message{
    long mtype;
    char mtext[256];
}message_t;

message_t recvmsg;
message_t sendmsg;
pthread_t tid1;
pthread_t tid2;
int msgid = 0;

void *thread1(void *arg)
{
    int ret = 0;
    char tmpbuff[4096] = {0};

    while(1)
    {
        sendmsg.mtype = 100L;
        m_fgets(sendmsg.mtext);
        ret = msgsnd(msgid, &sendmsg, sizeof(sendmsg) - sizeof(long), 0);
        if(-1 == ret)
        {
            perror("fail to msgsnd");
            return NULL;
        }
        if (0 == strcmp(sendmsg.mtext, ".quit"))
        {
            break;
        }
    }

    pthread_cancel(tid2);

    return NULL;
}

void *thread2(void *arg)
{
    ssize_t nret;

    while(1)
    {
        nret = msgrcv(msgid, &recvmsg, sizeof(recvmsg.mtext), 200L, 0);
        if(-1 == nret)
        {
            perror("fail to msgrcv");
            return NULL;
        }
        printf("RECV:%s\n", recvmsg.mtext);
        if (0 == strcmp(recvmsg.mtext, ".quit"))
        {
            break;
        }
    }

    pthread_cancel(tid1);

   return NULL;
}


int main(void)
{
    key_t key;
    int fd1 = 0;
    int fd2 = 0;

    key = ftok("/", 'a');
    if(-1 == key)
    {
        perror("fail to ftok");
        return -1;
    }
    printf("IPC对象键值:%#x\n", key);

    msgid = msgget(key, IPC_CREAT | 0664);
    if(-1 == msgid)
    {
        perror("fail to msgget");
        return -1;
    }
    printf("消息队列的ID:%d\n", msgid);

    pthread_create(&tid1, NULL, thread1, NULL);
    pthread_create(&tid2, NULL, thread2, NULL);

    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);

    msgctl(msgid, IPC_RMID, NULL);


    return 0;
}

二、共享内存

1.概念

        进程空间是独立的,共享内存是开辟一段内核空间,进程都映射到这一片空间上,实现空间的共享

        进程间通信最高效形式

2.操作方法

        创建IPC对象名称

        创建共享内存

        将进程空间地址映射到共享内存空间中

        读写共享内存空间实现进程间通信

        解除共享内存映射 

        删除共享内存

3.函数接口

①ftok

②shmget

原型:int shmget(key_t key, size_t size, int shmflg);
功能:
创建共享内存
参数:
key:IPC对象的键值
size:共享内存空间大小
shmflg:IPC_CREAT 不存在创建
IPC_EXCL 存放报错
返回值:
成功返回共享内存的ID号
失败返回-1

③shmat

原型:void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:
将进程空间中的地址映射到共享内存中
参数:
shmid:共享内存的ID号
shmaddr:
NULL:系统选择一个合适的地址进行映射
shmflg:
标志默认为0
返回值:
成功返回映射到共享内存空间中的地址
失败返回NULL

④shmdt

原型:int shmdt(const void *shmaddr);
功能:
解除映射
参数:
shmaddr:映射到共享内存空间中的地址
返回值:
成功返回0
失败返回-1

⑤shmctl

原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能:
向共享内存发送命令
参数:
shmid:共享内存ID号
cmd:命令
IPC_RMID 删除共享内存
buf:
默认为NULL
返回值:
成功返回0
失败返回-1

#include "../head.h"

int main(void)
{
    key_t key;
    int shmid = 0;
    int ret = 0;
    char *pshmaddr = NULL;

    key = ftok("/", 'a');
    if(-1 == key)
    {
        perror("fail to ftok");
        return -1;
    }

    shmid = shmget(key, 4096, IPC_CREAT | 0664);
    if(-1 == shmid)
    {
        perror("fail to shmget");
        return -1;
    }

    pshmaddr = shmat(shmid, NULL, 0);
    if(NULL == pshmaddr)
    {
        perror("fail to shamat");
        return -1;
    }

    while(1)
    {
        printf("pshmaddr = %s\n", pshmaddr);
        if(0 == strcmp(pshmaddr, ".quit"))
        {
            break;
        }
    }

    ret = shmdt(pshmaddr);
    if(-1 == ret)
    {
        perror("fail to shmdt");
        return -1;
    }

    shmctl(shmid, IPC_RMID, NULL);

    return 0;
}

三、信号灯

1.概念

搭配共享内存实现进程间通信

主要用于多进程任务间的同步

信号灯是一组信号量,即信号量的数组

用于线程间通信的信号量称为无名信号量,信号灯是有名信号量

2.信号灯操作

创建信号量数组

申请信号量

释放信号量

信号量的销毁

3.函数接口

①ftok

②semget

原型:int semget(key_t key, int nsems, int semflg);
功能:
创建信号量数组
参数:
key:IPC对象名称
nsems:信号量的个数
semflg:IPC_CREAT 不存在创建
IPC_EXCL 存在报错
返回值:
成功返回信号量数组的ID
失败返回-1

③semop

原型:int semop(int semid, struct sembuf *sops, size_t nsops);
功能:
完成对一个信号量的操作
参数:
semid:信号量数组的ID号
sops:对信号量进行操作的空间的首地址
nsops:对信号量进行操作的个数
返回值:
成功返回0
失败返回-1

④semctl

原型:int semctl(int semid, int semnum, int cmd, ...);
功能:
利用cmd实现对信号量的操作
参数:
semid:信号量数组的ID号
semnum:操作的信号量的下标
cmd:IPC_RMID 删除信号量
SETVAL 设置信号量的值
返回值:
成功返回0
失败返回-1
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};

#include "../head.h"

union semun{
    int              val;    
    struct semid_ds *buf;    
    unsigned short  *array;  
    struct seminfo  *__buf;
};                                                                                                  

int main(void)
{
    key_t key;
    int semid = 0;
    int ret = 0;
    union semun myun;
    struct sembuf mybuf;

    key = ftok("/", 'a');
    if(-1 == key)
    {
        perror("fail to ftok");
        return -1;
    }

    semid = semget(key, 2, IPC_CREAT | 0664);
    if(-1 == semid)
    {
        perror("fail to semget");
        return -1;
    }

    myun.val = 0;
    ret = semctl(semid, 0, SETVAL, myun);
    if (-1 == ret)
    {
        perror("fail to semctl");
        return -1;
    }

    myun.val = 1;
    ret = semctl(semid, 1, SETVAL, myun);
    if (-1 == ret)
    {
        perror("fail to semctl");
        return -1;
    }

    mybuf.sem_num = 1;
    mybuf.sem_op = -1;
    mybuf.sem_flg = SEM_UNDO;
    ret = semop(semid, &mybuf, 1);
    if(-1 == ret)
    {
        perror("fail to semop");
        return -1;
    }

    printf("申请写信号量成功\n");

    mybuf.sem_num = 0;
    mybuf.sem_op = +1;
    mybuf.sem_flg = SEM_UNDO;
    ret = semop(semid, &mybuf, 1);
    if(-1 == ret)
    {
        perror("fail to semop");
        return -1;
    }

    printf("释放读信号量\n");

    mybuf.sem_num = 0;
    mybuf.sem_op = -1;
    mybuf.sem_flg = SEM_UNDO;
    ret = semop(semid, &mybuf, 1);
    if(-1 == ret)
    {
        perror("fail to semop");
        return -1;
    }

    printf("申请读信号量成功\n");

    mybuf.sem_num = 0;
    mybuf.sem_op = +1;
    mybuf.sem_flg = SEM_UNDO;
    ret = semop(semid, &mybuf, 1);
    if(-1 == ret)
    {
        perror("fail to semop");
        return -1;
    }

    printf("释放读信号量\n");

    semctl(semid, 0, IPC_RMID, NULL);
    semctl(semid, 1, IPC_RMID, NULL);

    return 0;
}
基于数据驱动的 Koopman 算子的递归神经网络模型线性化,用于纳米定位系统的预测控制研究(Matlab代码实现)内容概要:本文围绕“基于数据驱动的Koopman算子的递归神经网络模型线性化”展开,旨在研究纳米定位系统的预测控制方法。通过结合数据驱动技术与Koopman算子理论,将非线性系统动态近似为高维线性系统,进而利用递归神经网络(RNN)建模并实现系统行为的精确预测。文中详细阐述了模型构建流程、线性化策略及在预测控制中的集成应用,并提供了完整的Matlab代码实现,便于科研人员复现实验、优化算法并拓展至其他精密控制系统。该方法有效提升了纳米级定位系统的控制精度与动态响应性能。; 适合人群:具备自动控制、机器学习或信号处理背景,熟悉Matlab编程,从事精密仪器控制、智能制造或先进控制算法研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①实现非线性动态系统的数据驱动线性化建模;②提升纳米定位平台的轨迹跟踪与预测控制性能;③为高精度控制系统提供可复现的Koopman-RNN融合解决方案; 阅读建议:建议结合Matlab代码逐段理解算法实现细节,重点关注Koopman观测矩阵构造、RNN训练流程与模型预测控制器(MPC)的集成方式,鼓励在实际硬件平台上验证并调整参数以适应具体应用场景。
提供了一套完整的基于51单片机的DDS(直接数字频率合成)信号波形发生器设计方案,适合电子爱好者、学生以及嵌入式开发人员学习和实践。该方案详细展示了如何利用51单片机(以AT89C52为例)结合AD9833 DDS芯片来生成正弦波、锯齿波、三角波等多种波形,并且支持通过LCD12864显示屏直观展示波形参数或状态。 内容概述 源码:包含完整的C语言编程代码,适用于51系列单片机,实现了DDS信号的生成逻辑。 仿真:提供了Proteus仿真文件,允许用户在软件环境中测试整个系统,无需硬件即可预览波形生成效果。 原理图:详细的电路原理图,指导用户如何连接单片机、DDS芯片及其他外围电路。 PCB设计:为高级用户准备,包含了PCB布局设计文件,便于制作电路板。 设计报告:详尽的设计文档,解释了项目背景、设计方案、电路设计思路、软硬件协同工作原理及测试结果分析。 主要特点 用户交互:通过按键控制波形类型和参数,增加了项目的互动性和实用性。 显示界面:LCD12864显示屏用于显示当前生成的波形类型和相关参数,提升了项目的可视化度。 教育价值:本资源非常适合教学和自学,覆盖了DDS技术基础、单片机编程和硬件设计多个方面。 使用指南 阅读设计报告:首先了解设计的整体框架和技术细节。 环境搭建:确保拥有支持51单片机的编译环境,如Keil MDK。 加载仿真:在Proteus中打开仿真文件,观察并理解系统的工作流程。 编译与烧录:将源码编译无误后,烧录至51单片机。 硬件组装:根据原理图和PCB设计制造或装配硬件。 请注意,本资源遵守CC 4.0 BY-SA版权协议,使用时请保留原作者信息及链接,尊重原创劳动成果。
【四轴飞行器的位移控制】控制四轴飞行器的姿态和位置设计内环和外环PID控制回路(Simulink仿真实现)内容概要:本文档详细介绍了基于Simulink仿真实现的四轴飞行器位移控制方法,重点在于设计内外环PID控制回路以实现对四轴飞行器姿态和位置的精确控制。文中阐述了控制系统的基本架构,内环负责稳定飞行器的姿态(如俯仰、滚转和偏航),外环则用于控制飞行器的空间位置和轨迹跟踪。通过Simulink搭建系统模型,实现控制算法的仿真验证,帮助理解飞行器动力学特性与PID控制器参数调节之间的关系,进而优化控制性能。; 适合人群:具备自动控制理论基础和Simulink使用经验的高校学生、科研人员及从事无人机控制系统的工程师;尤其适合开展飞行器控制、机器人导航等相关课题的研究者。; 使用场景及目标:①掌握四轴飞行器的动力学建模与控制原理;②学习内外环PID控制结构的设计与参数整定方法;③通过Simulink仿真验证控制策略的有效性,为实际飞行测试提供理论支持和技术储备;④应用于教学实验、科研项目或毕业设计中的控制系统开发。; 阅读建议:建议读者结合Simulink软件动手实践,逐步构建控制系统模型,重点关注PID参数对系统响应的影响,同时可扩展学习姿态传感器融合、轨迹规划等进阶内容,以全面提升飞行器控制系统的综合设计能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值