我正在实现基于std :: queue。
的C ++消息队列由于我需要popers在空队列中等待,我正在考虑使用互斥进行互斥,并且cond用于挂起空队列中的线程,因为glib会执行gasyncqueue。
然而,在我看来,互斥和信号量可以完成这项工作,我认为它包含一个整数,这似乎是一个非常高的数字,可以在待处理的消息上达到。
信号量的优点是你不需要每次从等待返回时手动检查条件,因为你现在确定有人插入了某些东西(当有人插入2个项目而你是第二个线程到达时)。
你会选择哪一个?
编辑: 更改了问题以回应@Greg Rogers
答案 0 :(得分:4)
单个信号量不起作用 - 您需要比较(互斥+信号量)和(互斥+条件变量)。
通过尝试实现它很容易看到:
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。
你应该使用你认为更容易实现的,我怀疑性能会有很大差异(尽管测量可能很有趣)。
答案 1 :(得分:0)
我个人使用互斥来序列化对列表的访问,并通过套接字(由socketpair()生成)发送一个字节来唤醒使用者。这可能比信号量或条件变量的效率稍低,但它的优点是允许使用者阻塞select()/ poll()。这样,如果需要,消费者还可以等待除数据队列之外的其他事物。它还允许您在几乎所有操作系统上使用完全相同的排队代码,因为几乎每个操作系统都支持BSD套接字API。
Psuedocode如下:
// 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;
}
答案 2 :(得分:-1)
如果您希望一次允许多个用户同时使用您的队列,则应使用信号量。
sema(10) // ten threads/process have the concurrent access.
sema_lock(&sema_obj)
queue
sema_unlock(&sema_obj)
Mutex一次只能“授权”一个用户。
pthread_mutex_lock(&mutex_obj)
global_data;
pthread_mutex_unlock(&mutex_obj)
这是主要区别,您应该决定哪种解决方案符合您的要求。 但我选择互斥方法,因为您不需要指定有多少用户可以获取您的资源。