实验3:利用Linux的消息队列通信机制实现三个线程间的通信

调用原型

POSIX信号量--无名信号量

POSIX信号量是Pthread线程库提供的一种同步机制,包括无名信号量和有名信号量两种机制。无名信号量,常用于多线程间的同步,也可用于相关进程间的同步(需置于相关进程间的共享内存区中)。有名信号量通过IPC名字进行进程间的同步,特点是把信号量保存在文件中,可用于线程、相关进程和不相关进程间的同步。

python 复制代码
#include <semaphore.h>
int sem_init(sem_t *sem,int pshared,unsigned int value)

创建无名信号量,sem(信号量名称),pshared一般为0(多线程间的同步),value(信号量的初始值)

int sem_wait(sem_t *sem)

阻塞申请资源

int sem_post(sem_t *sem)

释放资源

IPC消息队列通信机制

python 复制代码
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
消息缓冲区struct msgbuf

需重新定义

python 复制代码
struct msgbuf{
    long mtype;
    char mytext[1024];
}
int msgget(key_t key,int msgflag)

创建消息队列

int msgnd(int msqid,struct msgbuf* msgp,size_t msgsz,int msgflg)

发送消息

ssize_t msgrcv(int msqid,struct msgbuf* msgp,size_t msgsz,long msgtyp,int msgflg)

接收消息

int msgctl(int msqid,int cmd,struct msqid_ds* buf)

删除消息队列

Pthread线程库

python 复制代码
#include <pthread.h>
pthread_create()

创建线程

pthread_join()

阻塞等待进程

pthread_exit()

线程结束

具体实现

复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <pthread.h>
#include <unistd.h>

sem_t mutex_que;
sem_t over1,over2;
sem_t s_server,r_server;
sem_t msgid_mutex;

int msgid=-1;

struct msgbuf
{
    long mtype;
    char mytext[1024];
};

void* sender1(){
    int flag1=1;
    struct msgbuf buf;
    int error;
    while(flag1){
        memset(&buf,0,sizeof(buf));
        sem_wait(&s_server);
        sem_wait(&msgid_mutex);
        if(msgid==-1){
            msgid=msgget(0,IPC_CREAT);
            if(msgid==-1){
                printf("message queue error --sender1\n");
                sem_post(&msgid_mutex);
                exit(1);
            }
        }
        sem_post(&msgid_mutex);
        sem_wait(&mutex_que);
        printf("sender1> ");
        scanf("%s",buf.mytext);
        buf.mtype=1;
        if(!strncmp(buf.mytext,"exit",4)){
            flag1=0;
            strcpy(buf.mytext,"end1");
        }else{
            strcat(buf.mytext," --sender1");
        }
        error=msgsnd(msgid,&buf,sizeof(buf.mytext),IPC_NOWAIT);
        if(error==-1){
            printf("sender1 message send error\n");
            sem_post(&mutex_que);
            exit(1);
        }
        sem_post(&mutex_que);
        sem_post(&r_server);
    }
    //wait for signal over
    sem_wait(&s_server);
    sem_wait(&over1);
    sem_wait(&mutex_que);
    error=msgrcv(msgid,&buf,sizeof(buf.mytext),2,IPC_NOWAIT);
    if(!strncmp(buf.mytext,"over1",5)){
        printf("sender1: ");
        printf("%s --receiver\n",buf.mytext);
        sem_post(&mutex_que);
        sem_post(&s_server);
        pthread_exit(NULL);
    }
}

void* sender2(){
    int flag2=1;
    struct msgbuf buf;
    int error;
    while(flag2){
        memset(&buf,0,sizeof(buf));
        sem_wait(&s_server);
        sem_wait(&msgid_mutex);
        if(msgid==-1){
            sem_post(&s_server);
            sem_post(&msgid_mutex);
            continue;
        }
        sem_post(&msgid_mutex);
        sem_wait(&mutex_que);
        printf("sender2> ");
        scanf("%s",buf.mytext);
        buf.mtype=1;
        if(!strncmp(buf.mytext,"exit",4)){
            flag2=0;
            strcpy(buf.mytext,"end2");
        }else{
            strcat(buf.mytext," --sender2");
        }
        error=msgsnd(msgid,&buf,sizeof(buf.mytext),IPC_NOWAIT);
        if(error==-1){
            printf("sender2 message send error\n");
            sem_post(&mutex_que);
            exit(1);
        }
        sem_post(&mutex_que);
        sem_post(&r_server);
    }
    //wait for signal over
    sem_post(&s_server);
    sem_wait(&over2);
    sem_wait(&mutex_que);
    error=msgrcv(msgid,&buf,sizeof(buf.mytext),2,IPC_NOWAIT);
    if(!strncmp(buf.mytext,"over2",5)){
        printf("sender2: ");
        printf("%s --receiver\n",buf.mytext);
        sem_post(&mutex_que);
        sem_post(&s_server);
        pthread_exit(NULL);
    }
}

void* receiver(){
    int flag1=1;
    int flag2=1;
    struct msgbuf buf;
    int error;
    while(flag1!=0||flag2!=0){
        memset(&buf,0,sizeof(buf));
        sem_wait(&r_server);
        sem_wait(&mutex_que);
        error=msgrcv(msgid,&buf,sizeof(buf.mytext),1,IPC_NOWAIT);
        if(flag1&&!strncmp(buf.mytext,"end1",5)){
            memset(&buf,0,sizeof(buf));
            strcpy(buf.mytext,"over1");
            buf.mtype=2;
            error=msgsnd(msgid,&buf,sizeof(buf.mytext),IPC_NOWAIT);
            if(error==-1){
                printf("receiver send message error\n");
                sem_post(&mutex_que);
                exit(1);
            }
            sem_post(&over1);
            sem_post(&mutex_que);
            sem_post(&s_server);
            flag1=0;
        }else{
            if(flag2&&!strncmp(buf.mytext,"end2",5)){
                memset(&buf,0,sizeof(buf));
                strcpy(buf.mytext,"over2");
                buf.mtype=2;
                error=msgsnd(msgid,&buf,sizeof(buf.mytext),IPC_NOWAIT);
                if(error==-1){
                    printf("receiver send message error\n");
                    sem_post(&mutex_que);
                    exit(1);
                }
                sem_post(&over2);
                flag2=0;
                sem_post(&mutex_que);
                sem_post(&s_server);
            }
            else{
                if(strlen(buf.mytext)!=0){
                    printf("receive: %s \n",buf.mytext);
                    sem_post(&mutex_que);
                    sem_post(&s_server);
                }
            }
        }
    }
    printf("all end\n");
}

int main(){
    sem_init(&msgid_mutex,0,1);
    sem_init(&mutex_que,0,1);
    sem_init(&over1,0,0);
    sem_init(&over2,0,0);
    sem_init(&s_server,0,1);
    sem_init(&r_server,0,0);

    pthread_t s1,s2,r;
    int error;
    error=pthread_create(&s1,NULL,sender1,NULL);
    if(error!=0){
        printf("sender1 create error\n");
        exit(1);
    }
    error=pthread_create(&s2,NULL,sender2,NULL);
    if(error!=0){
        printf("sender2 create error\n");
        exit(1);
    }
    error=pthread_create(&r,NULL,receiver,NULL);
    if(error!=0){
        printf("receiver create error\n");
        exit(1);
    }

    //block wait threads end
    pthread_join(s1,NULL);
    pthread_join(s2,NULL);
    pthread_join(r,NULL);

    //delete message queue
    msgctl(msgid,IPC_RMID,0);
    //delete sem
    return 0;
}

实现效果

参考

1.参考实现
https://blog.csdn.net/CPromise/article/details/127929525

2.API手册
https://www.bookstack.cn/read/linuxapi/SUMMARY.md

3.sem信号量
https://blog.csdn.net/qq_19923217/article/details/82902442

相关推荐
你好潘先生11 小时前
别再记命令了,用 yeero do 说句人话就能跑脚本,而且不烧 token
服务器·python·命令行
orion571 天前
Missing Semester Class1:course overview and introduction of shell
linux
SkyWalking中文站1 天前
认识 Horizon UI · 6/17:Trace 探索器
运维·监控·自动化运维
用户120487221611 天前
Linux驱动编译与加载
linux·嵌入式
程序员老赵1 天前
服务器文件不想 SFTP 上传?Docker 跑个 File Browser,浏览器就能管理
服务器·docker·开源
火车叼位1 天前
写给初级开发者:SSL、SSH、HTTPS 与证书体系全解析
运维
vivo互联网技术1 天前
从 10 分钟到 1 秒:ES 深度分页任意跳页的三轮优化实战
服务器·数据库·redis·elasticsearch·深度分页
用户805533698031 天前
Input 子系统架构:Core、Handler、Driver 三层是怎么协作的
linux·嵌入式
用户805533698031 天前
RK-Forge外设系列开篇 - 把板子从「能启动」变成「能用」:Ethernet/SPI/MMC 三个纯接线外设
linux·github·嵌入式