v 之前发过利用创建子进程来实现消息队列互发消息,学过线程后,利用线程来实现一下消息队列互发消息,主要为了练习一下线程接口函数以及思考和利用进程实现互发消息有那些不同点。
v 下面直接贴代码,代码有注释,主要是写了与利用进程互发消息有那些不同点,关于消息队列的有些注释没有详细写,如果有朋友想要了解可以去我之前一篇博客看
v MsgQueue1.c
//利用线程间来实现之前的消息队列互发消息
//思考:与利用创建子进程来解决互发消息的不同点?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <pthread.h>
//键值
#define KEY 1234
//消息队列结构体定义
struct msgbuf
{
long mtype; //消息类型
char mbuf[100]; //消息内容
};
//不同点1:全局变量区
//结论:利用全局变量可以实现进程间通信
int msgid,ret;
struct msgbuf msgbuf;
pthread_t tid[2];
//发送消息处理函数
//发送消息的处理函数无多大变化,单独写出来会使程序更清晰
void *SendMsg(void *arg)
{
while(1)
{
scanf("%s",msgbuf.mbuf);
msgbuf.mtype = 1;
ret = msgsnd(msgid, &msgbuf, sizeof(msgbuf.mbuf),0);
if(-1 == ret)
{
perror("msgsnd");
exit(4);
}
if( !strncmp(msgbuf.mbuf, "end", 3))
{
msgbuf.mtype = 2;
ret = msgsnd(msgid, &msgbuf, sizeof(msgbuf.mbuf), 0);
break;
}
memset(msgbuf.mbuf, 0, sizeof(msgbuf.mbuf));
}
return (void *)8;
}
//接收消息处理函数
//分析结果与发送消息的函数差不多,但是其中有一个不同点列了出来
void *RcvMsg(void *arg)
{
while(1)
{
memset(msgbuf.mbuf, 0, sizeof(msgbuf.mbuf));
ret = msgrcv(msgid, &msgbuf, sizeof(msgbuf.mbuf), 2, 0);
if(-1 == ret)
{
perror("msgrcv");
exit(5);
}
if(!strncmp(msgbuf.mbuf, "end", 3))
{
//不同点:1.之前在父子进程中,父进程利用kill()接口函数结束了子进程
//2.在线程间是利用pthread_cancel()函数来结束另外一个线程
//结论:一个是利用 信号 进程间通信 ; 另外一个是利用 pthread_cancel()接口实现线程间通信
pthread_cancel(tid[0]);
break;
}
printf("Read from msgid = 2 :%s \n",msgbuf.mbuf);
}
return (void *)88;
}
int main()
{
//创建一个消息队列
msgid = msgget(KEY , IPC_CREAT | IPC_EXCL | 0666);
if(-1 == msgid)
{
perror("msgget");
exit(1);
}
//创建线程1:发送消息
ret = pthread_create(&tid[0], NULL, SendMsg , NULL);
if(ret)
{
perror("pthread_create1");
exit(2);
}
//创建线程2:接收消息
ret = pthread_create(&tid[1], NULL, RcvMsg, NULL);
if(ret)
{
perror("pthread_create2");
exit(3);
}
//等待线程1,2结束
pthread_join(tid[0],NULL);
pthread_join(tid[1],NULL);
//删除msgid标识的消息队列
ret = msgctl(msgid, IPC_RMID, NULL);
if(-1 == ret)
{
perror("msgctl");
exit(6);
}
return 0;
}
v MsgQueue2.c
//MsgQueue2.c 可以直接复制MsgQueue1.c 在其上修改
//修改点:1.msgget(KEY ,0 ); //消息队列不用再创建
//2.将相应的msgbuf.mbuf 的类型改一下
//3.利用msgctl()函数删除msgid标识的消息队列在magQueue1.c中已经实现,所以不用再写了
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <pthread.h>
//键值
#define KEY 1234
//消息队列结构体定义
struct msgbuf
{
long mtype;
char mbuf[100];
};
//全局变量区
int msgid,ret;
struct msgbuf msgbuf;
pthread_t tid[2];
//发送消息处理函数
void *SendMsg(void *arg)
{
while(1)
{
scanf("%s",msgbuf.mbuf);
msgbuf.mtype = 2;
ret = msgsnd(msgid, &msgbuf, sizeof(msgbuf.mbuf),0);
if(-1 == ret)
{
perror("msgsnd");
exit(4);
}
if( !strncmp(msgbuf.mbuf, "end", 3))
{
msgbuf.mtype = 1;
ret = msgsnd(msgid, &msgbuf, sizeof(msgbuf.mbuf), 0);
break;
}
memset(msgbuf.mbuf, 0, sizeof(msgbuf.mbuf));
}
return (void *)8;
}
//接收消息处理函数
void *RcvMsg(void *arg)
{
while(1)
{
memset(msgbuf.mbuf, 0, sizeof(msgbuf.mbuf));
ret = msgrcv(msgid, &msgbuf, sizeof(msgbuf.mbuf), 1, 0);
if(-1 == ret)
{
perror("msgrcv");
exit(5);
}
if(!strncmp(msgbuf.mbuf, "end", 3))
{
pthread_cancel(tid[0]);
break;
}
printf("Read from msgid = 1 : %s \n",msgbuf.mbuf);
}
return (void *)88;
}
int main()
{
msgid = msgget(KEY , 0);
if(-1 == msgid)
{
perror("msgget");
exit(1);
}
//创建线程1发送消息
ret = pthread_create(&tid[0], NULL, SendMsg , NULL);
if(ret)
{
perror("pthread_create1");
exit(2);
}
//创建线程2接收消息
ret = pthread_create(&tid[1], NULL, RcvMsg, NULL);
if(ret)
{
perror("pthread_create2");
exit(3);
}
//等待线程1,2
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
return 0;
}