利用Linux的消息队列通信机制实现两个线程间的通信

0. 相关博客

实现一个模拟的shell_ 一只博客-CSDN博客_操作系统实验模拟shellhttps://blog.csdn.net/qq_42276781/article/details/98521603实现一个管道通信程序_ 一只博客-CSDN博客_实现一个管道通信程序https://blog.csdn.net/qq_42276781/article/details/98523996利用Linux的共享内存通信机制实现两个进程间的通信_ 一只博客-CSDN博客_利用linux的共享内存通信机制实现两个进程间的通信https://blog.csdn.net/qq_42276781/article/details/98519201

1. 利用Linux的消息队列通信机制实现两个线程间的通信

       编写程序创建三个线程:sender1线程、sender2线程和receiver线程,三个线程的功能描述如下:

       ①sender1线程:运行函数sender1(),它创建一个消息队列,然后等待用户通过终端输入一串字符,并将这串字符通过消息队列发给receiver线程;可循环发送多个消息,直到用户输入“exit”为止,表示它不再发送消息,最后向receiver线程发送消息“end1”,并且等待receiver的应答(代码省略这步,sender2同),等到应答消息后,将接收到的应答信息显示在终端屏幕上,结束线程的运行。

       ②sender2线程:运行函数sender2(),共享sender1创建的消息队列,等待用户通过终端输入一串字符,并将这串字符通过消息队列发送给receiver线程;可循环发送多个消息,直到用户输入“exit”为止,表示它不再发送消息,最后向receiver线程发送消息“end2”,并且等待receiver的应答,等到应答消息后,将接收到的应答信息显示在终端屏幕上,结束线程的运行。

       ③receiver线程:运行函数receive(),它通过消息队列接收来自sender1和sender2两个线程的消息,将消息显示在终端屏幕上,当收到内容为“end1”的消息时,就向sender1发送一个应答消息“over1”;当收到内容为“end2”的消息时,就向sender2发送一个应答消息“over2”;消息接受完成后删除消息队列,结束线程的运行。选择合适的信号量机制实现三个线程之间的同步和互斥。

2. 原代码

无bug,可正常运行

 

 

3. 图片识别结果

有bug,无法直接运行,调试改bug过程中可以加深代码理解

test3.c

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
#include<sys/msg.h>
#include<semaphore.h>
pthread_t s1,s2,r;//创建线程sender1,sender2,receiver 
sem_t Write;//创建信号量变量 
struct msgbuff{//消息缓冲区 
	long mtype ;//消息类型 
	char mtext[100];//消息内容 
};
void *receive(void *arg){//arg即传入的msgid,下同 
	struct msgbuf buf;
	int ret;
	int flag1,flag2;//用于判断sender1、sender2是否结束发送 
	flag1=1;flag2=1;
	while(1){
		//消息队列初始化,将buf的sizeof(buf)字节置为0 
		memset(&buf,0,sizeof(buf));
		sem_wait(&Write);// 申请写的权限 
		//msgrcv即messagereceive,ret为返回值
		//函数原型 ssize_t msgrcv(int msgid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
		//arg即传入的msgid,msgp是指向消息缓冲区的指针,msgsz即messagesize
		//msgtyp即消息类型(可以自定义),msgflg即messageflag
		//具体参数含义参见https://baike.baidu.com/item/msgsnd/msgrcv
		ret=msgrcv(*(int *)arg,&buf,sizeof(buf.mtext),2,0);
		if (ret==-1){//返回值为-1表示接收失败 
			perror("msgrcv error");
			sem_post(&Write);//释放写的权限 
			exit(1);//异常退出程序 
		}
		else{//接收成功 
			printf("receive:%s\n",buf.mtext);//打印接收到的内容 
			sem_post(&Write);//释放写的权限 
			sleep(1);
		} 
		if(flag1&&!strncmp(buf.mtext,"end1",4)){
			pthread_cancel(s1);
			flag1--;//sender1发送结束 
		}
		else if(flag2&&!strncmp(buf.mtext,"end2",4)){
			pthread_cancel(s2);
			flag2--;//sender2结束发送 
		}
		if((flag1+flag2)==0){
			//sender1和sender2均发送结束 
			printf("---------end---------\n"); 
			exit(0); //正常退出程序 
		}
	}
}
 
void *sender1(void *arg){
	struct msgbuf buf;
	int ret;
	int x=1;
	while(x){
		memset(&buf,0,sizeof(buf));//初始化buf 
		sem_wait(&Write);//申请写的权限 
		scanf("%s",buf.mtext);//从键盘读入字符串 
		buf.mtype=2;//定义消息类型 
		//buf.mtext为exit,则将buf.mtext置为end1,并将x置0 
		if(!strncmp(buf.mtext,"exit",4)){	
			strcpy(buf.mtext,"end1");
			x=0;
		}
		//否则,在buf.mtext后加上//from s1 用以区分 
		else strcat(buf.mtext,"//from s1");
		//函数原型 int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); 
		ret=msgsnd(*(int *)arg,&buf,sizeof(buf.mtext),0);
		if(ret==-1){//返回值为-1,发送失败 
			perror("msgsnd error");
			sem_post(&Write);//释放写的权限 
			exit(1);//异常退出 
		}
		sem_post(&Write);//释放写的权限
		sleep(1);
	}
}
//sender1与sender2类似
void *sender2(void *arg){
	struct msgbuf buf;
	int ret;
	int x=1;
	while(x){
		memset(&buf,0,sizeof(buf));
		sem_wait(&Write);
		scanf("%s",buf.mtext);
		buf.mtype=2;
		if(!strncmp(buf.mtext,"exit",4)){	
			strcpy(buf.mtext,"end1");
			x=0;
		}
		else strcat(buf.mtext,"//from s2");
		ret=msgsnd(*(int *)arg,&buf,sizeof(buf.mtext),0);
		if(ret==-1){
			perror("msgsnd error");
			sem_post(&Write);
			exit(1);
		}
		sem_post(&Write);
		sleep(1);
	}
}
int main(){
	//ret即return的缩写,用来储存返回值 
	int ret,msgid,x;
	//int sem_init(sem_t *sem, int pshared, unsigned int value); 
	//sem为初始化的信号量名,pshare为0表示只在该进程的所有线程间共享,value为信号量的大小 
	//具体参数含义参见https://baike.baidu.com/item/sem_init 
	sem_init(&Write,0,1);
	
	//以下两行代码用以确保Write的初值为1,因为笔者在调试代码期间,有时Write的初值不为1 
	//如有需要可以使用这两行代码 
	/*sem_getvalue(&Write,&x);
	if(x==0) sem_post(&Write);*/ 
	
	key_ t key;
	key=100;//可以自定义key的大小
	//函数原型int msgget(key_t key, int msgflg);
	//具体参数含义参见https://baike.baidu.com/item/msgget
	msgid=msgget(key,IPC_CREAT|0666);
	if(msgid==-1){//msgid为-1表示创建消息队列失败 
		perror("msgid error");
		exit(1);
	}
	//创建线程,并将msgid传入
	//函数原型int pthread_create(pthread_t *tidp,const pthread_attr_t *attr
	//,(void*)(*start_rtn)(void*),void *arg);
	//*tidp为线程标识符的指针,*attr用以设置线程属性
	//第三个参数是线程运行函数的起始地址,*arg为传入运行函数的参数 
	//具体参数含义参见https://baike.baidu.com/item/pthread_create 
	ret=pthread_create(&r,NULL,receive,(void *)&msgid); 
	if (ret!=0){
		perror("receiver create error");
		exit(1);
	}
	
	ret=pthread_create(&s1,NULL,sender1,(void *)&msgid);
	if (ret!=0){
		perror("sender1 create error");
		exit(1);
	}
	
	ret=pthread_create(&s2,NULL,sender2,(void *)&msgid);
	if (ret!=0){
		perror("sender2 create error");
		exit(1);
	}
	//pthread_join等待一个线程结束
	//用法参见https://baike.baidu.com/item/pthread_join
	pthread_join(r,NULL);
	pthread_join(s1,NULL);
	pthread_join(s2,NULL);
	//删除消息队列
	//用法参见https://baike.baidu.com/item/msgctl
	msgctl(msgid,IPC_RMID,NULL);//ctl为control 
	return 0;	
}

4. 代码及实验报告获取


关注公众号,回复“进程管理”即可获取代码和实验报告

 

  • 2
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
Linux实现一个多线程安全的消息队列可以使用 POSIX 消息队列。POSIX 消息队列是一种在进程传递数据的机制,通过在进程传递消息来实现进程通信。它提供了在多个进程之传递数据的标准接口,并且支持多线程。 下面是一个简单的例子,展示如何使用 POSIX 消息队列实现线程安全的消息队列。 ```c++ #include <fcntl.h> #include <mqueue.h> #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define QUEUE_NAME "/my_queue" #define MAX_MESSAGES 10 #define MAX_MSG_SIZE 256 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; mqd_t mq_fd; void *producer(void *arg) { char buffer[MAX_MSG_SIZE]; int count = 0; while (1) { snprintf(buffer, MAX_MSG_SIZE, "Message %d", count++); pthread_mutex_lock(&mutex); mq_send(mq_fd, buffer, strlen(buffer) + 1, 0); pthread_mutex_unlock(&mutex); sleep(1); } } void *consumer(void *arg) { char buffer[MAX_MSG_SIZE]; unsigned int prio; while (1) { pthread_mutex_lock(&mutex); ssize_t bytes_read = mq_receive(mq_fd, buffer, MAX_MSG_SIZE, &prio); pthread_mutex_unlock(&mutex); if (bytes_read >= 0) { printf("Received message: %s\n", buffer); } else { perror("mq_receive"); } } } int main(int argc, char **argv) { struct mq_attr attr; attr.mq_flags = 0; attr.mq_maxmsg = MAX_MESSAGES; attr.mq_msgsize = MAX_MSG_SIZE; attr.mq_curmsgs = 0; mq_fd = mq_open(QUEUE_NAME, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, &attr); if (mq_fd == -1) { perror("mq_open"); exit(1); } pthread_t producer_thread, consumer_thread; pthread_create(&producer_thread, NULL, producer, NULL); pthread_create(&consumer_thread, NULL, consumer, NULL); pthread_join(producer_thread, NULL); pthread_join(consumer_thread, NULL); mq_close(mq_fd); mq_unlink(QUEUE_NAME); return 0; } ``` 在这个例子中,我们创建了一个 POSIX 消息队列,并且创建了两个线程来分别作为生产者和消费者。生产者线程不断地向队列发送消息,而消费者线程则从队列中接收消息。由于消息队列是多线程安全的,我们使用互斥锁来保护队列的访问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Toblerone_Wind

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值