linux线程间通信—消息队列

这篇文章介绍了Linux中使用消息队列进行进程间通信的函数,如msgget,msgsnd,msgrcv和msgctl,并提供了创建和管理消息队列的C语言代码示例,涉及线程的创建和同步。示例展示了如何在两个线程间通过消息队列交换数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

消息队列相关的函数

// 创建和获取 ipc 内核对象
int msgget(key_t key, int flags);
// 将消息发送到消息队列
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
// 从消息队列获取消息
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
// 查看、设置、删除 ipc 内核对象(用法和 shmctl 一样)
int msgctl(int msqid, int cmd, struct msqid_ds *buf);

消息数据格式(无论你是发送数据还是接收数据,消息的格式都得按照规范来)

struct Msg{
   long type; // 消息类型。这个是必须的,而且值必须 > 0,这个值被系统使用
   // 消息正文,多少字节随你而定
   // ...
};
//保证首4字节(32位linux下的long)是一个整数就行了,举例:
struct Msg {
    long type;
    char name[20];
    int age;
} msg;
    
struct Msg {
    long type;
    int start;
    int end;
} msg;
//正文部分是什么数据类型都没关系,因为消息队列传递的是 2 进制数据,不一定非得是文本

msgsnd函数

msgrcv函数

msgctl函数

例程1

#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
 
pthread_t pid_1,pid_2;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int msgid;
typedef struct{
    long mtype;
    int date;
}msg;
void *func2(void *arg)
{
    int i = 1,j =1;
    msg sendData;
    pthread_detach(pthread_self());
    while(1)
    {
        sleep(2);
        sendData.mtype = i++;
        sendData.date= j++;
        if(( msgsnd(msgid,&sendData,sizeof(msg)-sizeof(sendData.mtype),0))<0)
        {
            perror("msgsnd:");
            pthread_exit(NULL);
        }else
        {
            pthread_mutex_lock(&mutex);
            printf("send:mtype= %ld,data = %d\n",sendData.mtype,sendData.date);
            pthread_mutex_unlock(&mutex);
        }
 
    }
}
void *func1(void *arg)
{
    pthread_create(&pid_2,NULL,func2,NULL);
 
    msg reData;
    while(1)
    {
        if((msgrcv(msgid,&reData,sizeof(reData)-sizeof(reData.mtype),0,0))<0)
        {
            perror("msgrcv:");
            pthread_exit(NULL);
        }else{
            pthread_mutex_lock(&mutex);
            printf("recv:mtype= %ld,data = %d\n",reData.mtype,reData.date);
            pthread_mutex_unlock(&mutex);
        }
    }
    pthread_join(pid_2,NULL);
    printf("func1--son exit \n");
 
}
 
int main(int argc, char *argv[])
{
    if((msgid =  msgget(3123,IPC_CREAT|0666))<0)
    {
        perror("msgget:");
        return 0;
    }
    pthread_create(&pid_1,NULL,func1,NULL);
 
    pthread_join(pid_1,NULL);
    printf("main--son exit \n");
 
    printf("father exit\n");
    return 0;
}

例程2

MSGQUEUE1.c


#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define MSGKEY  1234
pthread_t tid[2]={0}; //定义一个数组,作为线程id

struct msgbuf 
{
    long mtype;     //消息类型
    char mtext[100];  //消息内容
};

void *receive(void *arg)
{
    struct msgbuf buf;  //定义结构体用作消息缓冲区
    int ret;

    while(1)
    {
        memset(&buf,0,sizeof(buf));  //初始化

        ret = msgrcv(*(int *)arg,&buf,sizeof(buf.mtext),2,0);
        if(-1 == ret)
        {
            perror("msgrcv");
            exit(1);
        }
        if(!strncmp(buf.mtext,"bye",3))
        {
            pthread_cancel(tid[1]); //注意:要取消另一个进程哦
            break;
        }
        printf("receive :%s\n",buf.mtext);
    }
}

void *send(void *arg)
{
    struct msgbuf buf;
    int ret,oldtype;

    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);//收到信号后立即执行取消动作(退出);oldtype用来存入取消动作的类型值。
    while(1)
    {
        memset(&buf,0,sizeof(buf));
        scanf("%s",buf.mtext);
        buf.mtype = 1;

        ret = msgsnd(*(int *)arg,&buf,sizeof(buf.mtext),0);
        if(-1 == ret)
        {
            perror("msgsnd");
            exit(1);
        }
        if(!strncmp(buf.mtext,"bye",3))
        {
            pthread_cancel(tid[0]);
            break;
        }
    }
}

int main()
{
    int msgid,ret;

    msgid = msgget(MSGKEY,IPC_CREAT |IPC_EXCL); //创建消息队列,返回标识符
    if(-1 == msgid)
    {
        perror("msgid");
        exit(1);
    }

    ret = pthread_create(&tid[0],NULL,receive,(void *)&msgid); //参数一:线程id;参数二:线程属性(通常为空);参数三:线程要执行的函数;参数四:作为传递给参数三的参数
    if(0 != ret)
    {
        perror("pthread_create1");
        exit(1);
    }

    ret = pthread_create(&tid[1],NULL,send,(void *)&msgid);
    if(0 != ret)
    {
        perror("msgid");
        exit(1);
    }

    pthread_join(tid[0],NULL);//阻塞调用线程,直到指定的线程终止
    pthread_join(tid[1],NULL);

    msgctl(msgid,IPC_RMID,NULL);//移除消息队列
    return 0;
}

例程3


#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define MSGKEY  1234
pthread_t tid[2]={0}; //定义一个数组,作为线程id

struct msgbuf 
{
    long mtype;     //消息类型
    char mtext[100];  //消息内容
};

void *receive(void *arg)
{
    struct msgbuf buf;  //定义结构体用作消息缓冲区
    int ret;

    while(1)
    {
        memset(&buf,0,sizeof(buf));  //初始化

        ret = msgrcv(*(int *)arg,&buf,sizeof(buf.mtext),1,0);
        if(-1 == ret)
        {
            perror("msgrcv");
            exit(1);
        }
        if(!strncmp(buf.mtext,"bye",3))
        {
            pthread_cancel(tid[1]); //注意:要取消另一个进程哦
            break;
        }
        printf("receive another:%s\n",buf.mtext);
    }
}

void *send(void *arg)
{
    struct msgbuf buf;
    int ret,oldtype;

    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);//收到信号后立即执行取消动作(退出);oldtype用来存入取消动作的类型值。
    while(1)
    {
        memset(&buf,0,sizeof(buf));
        scanf("%s",buf.mtext);
        buf.mtype = 2;

        ret = msgsnd(*(int *)arg,&buf,sizeof(buf.mtext),0);
        if(-1 == ret)
        {
            perror("msgsnd");
            exit(1);
        }
        if(!strncmp(buf.mtext,"bye",3))
        {
            pthread_cancel(tid[0]);
            break;
        }
    }
}

int main()
{
    int msgid,ret;

    msgid = msgget(MSGKEY,0); //创建消息队列,返回标识符
    if(-1 == msgid)
    {
        perror("msgid");
        exit(1);
    }

    ret = pthread_create(&tid[0],NULL,receive,(void *)&msgid); //参数一:线程id;参数二:线程属性(通常为空);参数三:线程要执行的函数;参数四:作为传递给参数三的参数
    if(0 != ret)
    {
        perror("pthread_create1");
        exit(1);
    }

    ret = pthread_create(&tid[1],NULL,send,(void *)&msgid);
    if(0 != ret)
    {
        perror("msgid");
        exit(1);
    }

    pthread_join(tid[0],NULL);//阻塞调用线程,直到指定的线程终止
    pthread_join(tid[1],NULL);

    return 0;
}




执行结果:
    receive :hi         hi
    receive :i          i am your father
    receive :am         receive another:fuck
    receive :your       receive another:what
    receive :father     receive another:you
    fuck                receive another:say
    what you say
    bye
### 嵌入式 Linux 线程间通信消息队列实现 #### 消息队列概述 在嵌入式Linux环境下,线程间通信可以通过多种方式进行,其中一种高效的方式就是使用消息队列消息队列是一种跨进程的数据结构,允许一个或多个进程向队列中放入消息,并由其他进程读取这些消息[^4]。 #### 创建和初始化消息队列 为了在线程之间建立有效的通信通道,首先需要创建并初始化一个消息队列: ```c #include <mqueue.h> #include <fcntl.h> /* For O_* constants */ #include <sys/stat.h> /* For mode constants */ // 定义消息队列名称 #define QUEUE_NAME "/my_queue" // 设置最大消息数量和每条消息的最大长度 #define MAX_MESSAGES 10 #define MESSAGE_SIZE 256 mqd_t mq; // 打开或创建一个新的消息队列 struct mq_attr attr; attr.mq_flags = 0; attr.mq_maxmsg = MAX_MESSAGES; attr.mq_msgsize = MESSAGE_SIZE; attr.mq_curmsgs = 0; mq = mq_open(QUEUE_NAME, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, &attr); if (mq == (mqd_t)-1) { perror("Failed to open message queue"); } ``` 这段代码展示了如何定义消息队列的相关参数,并尝试打开已存在的同名消息队列;如果不存在,则按照指定属性创建新的消息队列[^5]。 #### 发送消息至消息队列 一旦成功建立了消息队列,就可以通过`mq_send()`函数来发送消息给目标队列: ```c char *message = "Hello from sender thread!"; ssize_t msg_len = strlen(message); if (mq_send(mq, message, msg_len, 0) != 0){ perror("Message send failed"); } printf("Sent %zd bytes\n", msg_len); ``` 这里展示了一个简单的例子,在此例中,字符串形式的消息被写入之前创建好的消息队列中。 #### 接收来自消息队列的消息 接收端可以调用`mq_receive()`从消息队列里获取最新的消息: ```c char buffer[MESSAGE_SIZE]; unsigned int priority; ssize_t num_bytes_received = mq_receive(mq, buffer, sizeof(buffer), &priority); if(num_bytes_received >= 0){ printf("Received message: \"%s\"\n", buffer); } else { perror("Receive error"); } // 关闭消息队列 mq_close(mq); ``` 上述代码片段实现了从消息队列中读取消息的功能,并将其内容打印出来。最后记得关闭不再使用的消息队列以释放资源。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值