IPC Unix消息队列线程安全吗?

时间:2019-03-31 16:54:08

标签: c++ linux message-queue

我做了下面的代码,以了解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;
    }

卡在上面的行中不确定为什么吗?

1 个答案:

答案 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;

因此您需要区分是否已读取消息,没有可用消息或发生错误,这需要结束线程。