代码之家  ›  专栏  ›  技术社区  ›  Arkaitz Jimenez

什么对消息队列更好?mutex&cond还是mutex&semaphore?

  •  2
  • Arkaitz Jimenez  · 技术社区  · 16 年前

    我正在执行一个基于STD::队列的C++消息队列。

    因为我需要poper等待一个空队列,所以我考虑使用mutex进行互斥,并使用cond挂起空队列上的线程,就像glib对gasyncqueue所做的那样。

    不过,在我看来,互斥信号灯可以完成这项工作,我认为它包含一个整数,对于待处理的消息来说,这个数字似乎相当高。

    信号量的优点是,您不需要每次从等待返回时手动检查条件,因为您现在确定有人插入了某些内容(当有人插入了2个项目,而您是第二个线程到达时)。

    你会选哪一个?

    编辑: 回答@greg rogers时更改了问题

    3 回复  |  直到 16 年前
        1
  •  4
  •   Greg Rogers    16 年前

    一个信号量不能完成这项工作-您需要进行比较 (互斥+信号量) (互斥+条件变量) .

    通过尝试实现它,很容易看到这一点:

    void push(T t)
    {
        queue.push(t); 
        sem.post();
    }
    
    T pop()
    {
        sem.wait();
        T t = queue.top();
        queue.pop();
        return t;
    }
    

    正如您所看到的,当您实际读/写队列时,没有互斥,即使存在(来自信号量的)信号。多个线程可以同时调用push并中断队列,或者多个线程可以同时调用pop并中断队列。或者,一个线程可以调用pop并删除队列的第一个元素,而另一个线程则调用push。

    您应该使用您认为更容易实现的工具,我怀疑性能会有很大的变化(不过,度量它可能很有趣)。

        2
  •  0
  •   Jeremy Friesner    16 年前

    我个人使用互斥体来序列化对列表的访问,并通过在套接字上发送一个字节(由socketpair()生成)来唤醒使用者。这可能比信号量或条件变量的效率要低一些,但它的优点是允许使用者在select()/poll()中阻塞。这样,如果消费者愿意的话,它也可以在数据队列之外等待其他事情。它还允许您在几乎所有操作系统上使用完全相同的排队代码,因为几乎每个操作系统都支持BSD套接字API。

    伪代码如下:

    // Called by the producer.  Adds a data item to the queue, and sends a byte
    // on the socket to notify the consumer, if necessary
    void PushToQueue(const DataItem & di)
    {
       mutex.Lock();
       bool sendSignal = (queue.size() == 0);
       queue.push_back(di);
       mutex.Unlock();
       if (sendSignal) producerSocket.SendAByteNonBlocking();
    }
    
    // Called by consumer after consumerSocket selects as ready-for-read
    // Returns true if (di) was written to, or false if there wasn't anything to read after all
    // Consumer should call this in a loop until it returns false, and then
    // go back to sleep inside select() to wait for further data from the producer
    bool PopFromQueue(DataItem & di)
    {
       consumerSocket.ReadAsManyBytesAsPossibleWithoutBlockingAndThrowThemAway();
       mutex.Lock();
       bool ret = (queue.size() > 0);
       if (ret) queue.pop_front(di);
       mutex.Unlock();
       return ret;
    }
    
        3
  •  -1
  •   bua    16 年前

    如果您希望同时允许多个用户使用您的队列,那么应该使用信号量。

    sema(10) // ten threads/process have the concurrent access.
    
    sema_lock(&sema_obj)
    queue
    sema_unlock(&sema_obj) 
    

    互斥体一次只能“授权”一个用户。

    pthread_mutex_lock(&mutex_obj)
    global_data;
    pthread_mutex_unlock(&mutex_obj) 
    

    这是主要的区别,您应该决定哪个解决方案适合您的需求。 但我会选择mutex方法,因为您不需要指定有多少用户可以获取您的资源。