我做了下面的代码,以了解Linux中消息队列的线程安全性。但不确定为什么程序会卡住。虽然在应用适当的锁定后它不会卡住。但是,如果消息队列是线程安全的,那么为什么程序会卡住。或者我在那里错过了一个窍门?小小的帮助或建议将对您有深远的帮助。
/admin
下面是短路输出端
#include <cstdio>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <cstdlib>
#include <cstring>
#include <errno.h>
#include <iostream>
#include <string>
#include <thread>
using namespace std;
struct mesg_buffer // MQ Structure
{
long mesg_type;
char mesg_text[100];
};
class MQ_Wrapper // Wrapper class
{
key_t key;
int msgid;
public:
MQ_Wrapper()
{
key = ftok("progfiles_other", 65); // creating key
msgid = msgget(key, 0666 | IPC_CREAT ); // creating message
// queue id
}
~MQ_Wrapper() // removing mqueue in destructor
{
remove_queue();
}
void remove_queue() // removing m queue
{
msgctl(msgid, IPC_RMID, NULL);
}
bool receive_message() // For receiving mesd
{
mesg_buffer message;
if( msgrcv(msgid, &message, sizeof(message), 0, IPC_NOWAIT) != -1 )
{
printf("Data Received is : %s \n",message.mesg_text);
}
else
{
printf("Receving Failed : "); //p
return false;
}
return true;
}
void send_message(int count)
{
mesg_buffer message;
message.mesg_type = count;
char str[25];
sprintf(str,"Hello Friends %ld",message.mesg_type);
strcpy(message.mesg_text,str);
if (msgsnd(msgid, &message, sizeof(message), 0) == 0)
{
printf("Data send is : %s \n", message.mesg_text);
// getting stuck here
}
else
{
printf("Sending Failed\n");
}
}
};
MQ_Wrapper mq; // Global object
// all local variables used
void send_func(bool status)
{
for(int i = 1 ; i < 501 ; i++)
{
if(i%2 == status)
mq.send_message(i);
}
}
void receive_func()
{
while(1) // infinite loop
{
if (mq.receive_message() == false)
break;
}
}
int main()
{
thread send1(send_func,true); // thread 1
thread send2(send_func,false); // thread 2
thread receive1(receive_func); // thread 3
thread receive2(receive_func); // thread 4
send1.join();
send2.join();
receive1.join();
receive2.join();
return 0;
}
卡在上面的行中不确定为什么吗?
答案 0 :(得分:0)
您的问题-恕我直言-与线程无关。当您调用msgsnd()
时,消息将被写入全局队列。队列的大小限制为定义的大小,以在没有可用的读取器的情况下防止系统溢出。
在msgsnd()
的手册页中
如果队列中没有足够的空间,则
msgsnd()
的默认行为是阻止,直到空间可用为止。
在msgrcv()
的手册页中:
msgrcv()
系统调用从msqid指定的队列中删除一条消息,并将其放入msgp指向的缓冲区中。
在您的情况下,receive_func
都失败并退出,并且从那时起,没有人正在从该队列中读取数据,该队列已满,msgsnd()
将会满载阻塞,直到队列再次有空间。
如果您使用IPC_NOWAIT
,则需要测试所得到的错误是否为ENOMSG
,并且不退出线程而是执行例如睡觉:
IPC_NOWAIT
如果队列中没有请求类型的消息,则立即返回。将errno
设置为ENOMSG
时,系统调用失败。
在当前代码中,如果当前没有可用消息,则只需退出文件循环:
if (mq.receive_message() == false)
break;
因此您需要区分是否已读取消息,没有可用消息或发生错误,这需要结束线程。