9

I'm implementing a thread with a queue of tasks. As soon as as the first task is added to the queue the thread starts running it.

Should I use pthread condition variable to wake up the thread or there is more appropriate mechanism?

If I call pthread_cond_signal() when the other thread is not blocked by pthread_cond_wait() but rather doing something, what happens? Will the signal be lost?

Good Person
  • 1,437
  • 2
  • 23
  • 42
jackhab
  • 17,128
  • 37
  • 99
  • 136

5 Answers5

13

Semaphores are good if-and-only-if your queue already is thread safe. Also, some semaphore implementations may be limited by top counter value. Even it is unlikely you would overrun maximal value.

Simplest and correct way to do this is following:

pthread_mutex_t queue_lock;
pthread_cond_t  not_empty;
queue_t queue;

push()
{
  pthread_mutex_lock(&queue_lock);
  queue.insert(new_job);
  pthread_cond_signal(&not_empty)
  pthread_mutex_unlock(&queue_lock);
}
pop()
{
  pthread_mutex_lock(&queue_lock);
  if(queue.empty()) 
     pthread_cond_wait(&queue_lock,&not_empty);
  job=quque.pop();
  pthread_mutex_unlock(&queue_lock);
}
  • 14
    `pthread_cond_wait` can return spuriously, so the `if` in `pop()` should be a `while`. – Robie Basak Feb 26 '11 at 08:49
  • 6
    Furthermore, the arguments to `pthread_cond_wait` are probably in wrong order - reference to the condition should be first, lock second. – vektor Sep 26 '12 at 13:35
  • 1
    Why signalling from the inside of the critical section? It is a good recipe for deadlock. For example: https://stackoverflow.com/questions/44502050/get-stuck-executing-multithreads-pthread-on-windows – ArturFH Jun 13 '17 at 22:13
12

From the pthread_cond_signal Manual:

The pthread_cond_broadcast() and pthread_cond_signal() functions shall have no effect if there are no threads currently blocked on cond.

I suggest you use Semaphores. Basically, each time a task is inserted in the queue, you "up" the semaphore. The worker thread blocks on the semaphore by "down"'ing it. Since it will be "up"'ed one time for each task, the worker thread will go on as long as there are tasks in the queue. When the queue is empty the semaphore is at 0, and the worker thread blocks until a new task arrives. Semaphores also easily handle the case when more than 1 task arrived while the worker was busy. Notice that you still have to lock access to the queue to keep inserts/removes atomic.

Joao da Silva
  • 7,353
  • 2
  • 28
  • 24
1

The signal will be lost, but you want the signal to be lost in that case. If there is no thread to wakeup, the signal serves no purpose. (If nobody is waiting for something, nobody needs to be notified when it happens, right?)

With condition variables, lost signals cannot cause a thread to "sleep through a fire". Unless you actually code a thread to go to sleep when there's already a fire, there is no need to "save a signal". When the fire starts, your broadcast will wake up any sleeping threads. And you would have to be pretty daft to code a thread to go to sleep when there's already a fire.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
0

As already suggested, semaphores should be the best choice. If you need a fixed-size queue just use 2 semaphores (as in classical producer-consumer).

In artyom code, it would be better to replace "if" with "while" in pop() function, to handle spurious wakeup.

mp81ss
  • 1
0

No effects.

If you check how pthread_condt_signal is implemented, the condt uses several counters to check whether there are any waiting threads to wake up. e.g., glibc-nptl

 /* Are there any waiters to be woken?  */
 if (cond->__data.__total_seq > cond->__data.__wakeup_seq){
    ...
 }
pepero
  • 7,095
  • 7
  • 41
  • 72