linux进程,线程之间通信方式之一,共享队列
1.概念
在系统内核中,实现了一种链表结构的共享队列,各节点挂接可能不是同一种类型的数据结构信息,但是在每个结构数据都是指明该消息的类型的,如下结构:
typedef struct msg {
long type; // 消息的类型
char name[33];
}MSG;
如上结构,type表示的是当前消息的类型,整形数标记。这样做的好处是,使用者可以根据自己实际业务情况,设置自定义的数据格式,方便灵活。
2.共享队列的方法介绍以及使用举例:
int msgget(key_t key, int msgflg);
返回值: 成功返回队列的id,失败返回-1,msgflag的取值如下所示:
key:通过fotk方法生成对应的key,用于创建队列时的标示参数。( key_t ftok(const char *pathname, int proj_id); pathname:路径,proj_id可自己指定)
msgflag:该单数去|运算结果,
IPC_CREAT:获取一个队列的,不存在就创建
IPC_EXCL:跟创建配和使用,在获取队列id时,队列存在直接返回错误。
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
返回值:0 表示成功,-1 失败并设置 errno。
msgid:msgget方法返回的消息id
msgp;具体消息结构,
msgsz:具体消息的大小(字节)
msgflag:可选项,具体区分:
0:当消息队列满时,msgsnd将会阻塞,直到消息能写进消息队列或者消息队列被删除。
IPC_NOWAIT:当消息队列满了,msgsnd函数将不会等待,会立即出错返回EAGAIN
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
int msgflg);
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
int msgflg);
msgid:消息队列id
msgp:出参,消息结构,
msgsz;消息的大小。
msgtyp: 分为三种情况,如下:
== 0:返回队列中第一个元素。
> 0:返回类型为msgtyp的第一个消息。
< 0 返回队列中消息类型值小于等于type绝对值的消息,如果这种消息有若干个,则取类型值最小的消息
flag:可以为0、IPC_NOWAIT、IPC_EXCEPT
为0时,阻塞式接收消息,没有该类型的消息msgrcv函数一直阻塞等待
为IPC_NOWAIT时,如果没有返回条件的消息调用立即返回,此时错误码为ENOMSG
为IPC_EXCEPT时,与msgtype配合使用返回队列中第一个类型不为msgtype的消息,可用于过滤掉不需要的消息.
返回值:成功返回消息数据部分的长度;错误返回-1
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
msgid:队列id
cmd:操作处理的命令,如下:
IPC_STAT:取此队列的msqid_ds结构,并将它存放在buf指向的结构中
IPC_RMID;删除消息队列。
IPC_SET:改变消息队列的状态,把buf所指的msqid_ds结构中的uid、gid、mode复制到消息队列的msqid_ds结构内。(内核为每个消息队列维护着一个结构,结构名为msqid_ds,里面存放着消息队列的大小,pid,存放时间等一些参数)具体结构类型见如下:
struct msqid_ds {
struct ipc_perm msg_perm; /* Ownership and permissions */
time_t msg_stime; /* Time of last msgsnd(2) */
time_t msg_rtime; /* Time of last msgrcv(2) */
time_t msg_ctime; /* Time of last change */
unsigned long __msg_cbytes; /* Current number of bytes in
queue (nonstandard) */
msgqnum_t msg_qnum; /* Current number of messages
in queue */
msglen_t msg_qbytes; /* Maximum number of bytes
allowed in queue */
pid_t msg_lspid; /* PID of last msgsnd(2) */
pid_t msg_lrpid; /* PID of last msgrcv(2) */
};
struct ipc_perm {
key_t __key; /* Key supplied to msgget(2) */
uid_t uid; /* Effective UID of owner */
gid_t gid; /* Effective GID of owner */
uid_t cuid; /* Effective UID of creator */
gid_t cgid; /* Effective GID of creator */
unsigned short mode; /* Permissions */
unsigned short __seq; /* Sequence number */
};
3,消息队列使用举例。
发送方:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <iostream>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <pthread.h>
#define MSG_QUEUE_NAME "wechat"
// 消息结构
typedef struct msg {
long type; // 消息的类型
char name[128];
}MSG;
typedef struct threadArgs {
long type;
int msgId;
}ThreadArgs;
void * threadProcess(void* args) {
ThreadArgs pargs = *(ThreadArgs*)(args);
printf("我是线程,我的ID = %lu - %lu\n", pthread_self(),pargs.type);
int count = 0;
for(;;){
MSG msg;
msg.type = pargs.type; // 消息类型
sprintf(msg.name,"Msg type is %lu,number is %d,threadId %lu",msg.type,count++,pthread_self());
int ret = msgsnd(pargs.msgId, (void*)&msg, sizeof(msg),IPC_NOWAIT); // 不等待直接写入队列,如果队列满,直接返回队列满错误编码
if(ret == -1) {
printf("add msg is failed,is,errno = %d\n",errno);
sleep(1);
continue;
}
printf("add msg type is %s\n",msg.name);
sleep(1);
}
printf("thread end --->%d",pargs.type);
}
int main() {
key_t key;
key = ftok("./",100);
if(key == -1) {
perror("ftok");
return -1;
}
int msgPID;
msgPID = msgget(key,IPC_CREAT|0666); // 获取一个队列
if(msgPID == -1) {
perror("msgget");
return -1;
}
pthread_t pidArr[3];
for(int i = 0;i < 3;++i){
ThreadArgs args;
args.type = i + 1; // 消息类型
args.msgId = msgPID; // 队列id
printf("msgid is %d-%d\n",args.type,args.msgId);
int ret = pthread_create(&pidArr[i],NULL,threadProcess,(void*)&args);//如果穿参数,考虑变量共享的情况。避免出现意想不到的结构。
if (ret != 0){
continue;
sleep(1);
}
}
for(int i = 0;i < 1;++i){
pthread_join(pidArr[i],NULL);
}
while(true) {
sleep(1);
}
// 结束删除掉该队列
struct msqid_ds buff;
int ret = msgctl(msgPID,IPC_RMID,&buff);
if (ret == -1){
return -1;
}
return 0;
}
接收方:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <iostream>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <pthread.h>
#define THR 3
typedef struct msg {
long type;
char name[128];
}MSG;
typedef struct threadArgs {
long type;
int msgId;
}ThreadArgs;
void * threadProcess(void* args) {
ThreadArgs pargs = *(ThreadArgs*)(args);
long int msgtype = pargs.type;
while(true) {
MSG msg;
int ret = msgrcv(pargs.msgId,(void*)&msg,sizeof(msg),msgtype,0);
if(ret == -1){
continue;
sleep(1);
}
printf("_+_+ %s\n",msg.name);
sleep(1);
}
}
int main(){
long int msgtype = 1;
key_t key;
key = ftok("./",100);
if(key == -1) {
perror("ftok");
return -1;
}
int msgid = msgget(key,IPC_CREAT|0666);
if (msgid == -1){
return -1;
}
pthread_t pidArr[3];
for(int i = 0;i < THR;++i){
ThreadArgs args;
args.type = i + 1; // 制定消息类型
args.msgId = msgid; // 队列id
int ret = pthread_create(&pidArr[i],NULL,threadProcess,(void*)&args);
// printf("create a thread is %d\n",i);
if (ret != 0){
continue;
}
}
for(int i = 0;i < THR;++i){
pthread_join(pidArr[i],NULL);
}
while(true) {
sleep(1);
}
return 0;
}