What's the best for a message queue? mutex & cond or mutex and semaphore?
I am implementing a C ++ message queue based on std :: queue.
Since I need posts to wait on an empty queue, I considered using the mutex and cond mutual exclusion to suspend threads on an empty queue, since glib does this using gas synchronization.
However, it seems to me that mutex & semaphore will do the job, I think it contains an integer and seems to be quite a large number for pending messages.
The upsides of the semaphore are that you don't have to manually check the condition every time you return from the wait, since now you are sure that someone has inserted something (when someone has inserted 2 elements and you are the second thread ).
Which one will you choose?
EDIT: Changed question in response to @Greg Rogers
source to share
A single semaphore doesn't do the job - you need to compare (mutex + semaphore) and (state variable mutex +) .
It's pretty easy to see when trying to implement it:
void push(T t)
{
queue.push(t);
sem.post();
}
T pop()
{
sem.wait();
T t = queue.top();
queue.pop();
return t;
}
As you can see, there is no mutual exclusion when you actually read / write to the queue, even though there is a signaling (from the semaphore). Multiple threads can call push and split the queue at the same time, or multiple threads can call pop and split at the same time. Or a thread can call pop and remove the first item in the queue, while another thread is called push.
You should use what you think is easier to implement, I doubt the performance will be much different, if any (it might be interesting to measure at least).
source to share
Personally, I use a mutex to serialize the list access and wake up the consumer by sending a byte over the socket (created by socketpair ()). This can be somewhat less efficient than a semaphore or condition variable, but has the advantage of allowing the user to block select () / poll (). This way the consumer can also wait for other things besides the data queue if he wants. It also allows the same queuing code to be used for almost all OSs, since virtually every OS supports BSD APIs.
Psuedocode follows:
// 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;
}
source to share
If you want to allow multiple concurrent users to use your queue at the same time, you must use semaphores.
sema(10) // ten threads/process have the concurrent access.
sema_lock(&sema_obj)
queue
sema_unlock(&sema_obj)
Mutex will only "authorize" one user at a time.
pthread_mutex_lock(&mutex_obj) global_data; pthread_mutex_unlock(&mutex_obj)
This is the main difference and you must decide which solution will suit your requirements. But I would take the mutex approach because you don't need to specify how many users can grab your resource.
source to share