I've found the following topic (here) about pthreads but there are many good solutions.
I wanted to know if the following piece of code is valid and if so, why the same lock is used to call pthread_cond_wait as well as access it and then unlocked right away:
void suspendMe()
{
pthread_mutex_lock(&m_SuspendMutex);
pthread_cond_wait(&m_ResumeCond, &m_SuspendMutex);
pthread_mutex_unlock(&m_SuspendMutex);
}
Would it not be better to use 2 separate mutexes here, or is this the correct way to suspend a pthread??
Thanks in advance!
EDIT:
Awesome replies, thanks all. Just one more related question. Since I want to resume a thread separately in another function, would this be more proper in resuming it?
void suspendMe()
{
pthread_mutex_lock(&m_SuspendMutex);
pthread_cond_wait(&m_ResumeCond, &m_SuspendMutex);
}
void resumeMe()
{
pthread_cond_signal(&m_ResumeCond);
pthread_mutex_unlock(&m_SuspendMutex);
}
Thanks again everyone!! :~)
Actually, this code isn't thread safe. The mutex isn't actually protecting anything, leaving the implied predicate vulnerable to race conditions.
Look at this code -- what is the mutex protecting? What protects the suspend/resume state?
This is correct:
The thread should call
checkSuspend
at safe points where it can be suspended. Other threads can callsuspendMe
andresumeMe
to suspend/resume the thread.Notice that now the mutex protects the
m_SuspendFlag
variable, ensuring that the thread is told to suspend, told to resume, and checks whether it should suspend or stay suspended under protection, making the code thread-safe.Using two mutexes would defeat the entire point of condition variables. The whole mechanism by which they work is that you can check whether there is something you should wait for and then atomically wait for it without either holding the lock while you wait or having to release the lock and then wait. If you hold the lock while you wait, how can any other thread change the state? And if you release the lock and then wait, what happens if you miss the change in state?
By the way, it almost never makes sense to pause or resume a thread. If you feel like you need to pause a thread from the outside, that just indicates that you coded the thread to do something you didn't actually want it to do. Questions about pausing or resuming threads often indicate an incorrect mental model of thread programming. A thread might need to wait for something, but it shouldn't be "paused" from the outside because it should already know by its own coding when it shouldn't do some particular bit of work.
This is the correct way.
pthread_cond_wait
unlocksm_SuspendMutex
, then waits onm_ResumeCond
and then locksm_SuspendMutex
again before returning.The reason it works this way is because condition variables are used to signal a change of some state, and since this state is shared it must be locked while some thread is accessing it. E.g. consider implementing a queue of events:
Note that:
qu
is synchronized using themutex
.mutex
in order to allow the other threads to add items to the queue, and when it have been changed we must lock themutex
again to actually inspect the queue. This is exactly whatpthread_cond_signal
does.Yes.
The
pthread_cond_wait()
requires a locked mutex. This is because of the way condition varaibles are used. Normally they are used like this:So you acquire the lock saying you want to modify the resources protected by the lock. But if the object is not in a
ready()
state then you suspend your thread withpthread_cond_wait()
which suspends the thread and unlocks the mutex (thus allowing other threads to aquire the lock and potentially transform the object into aready()
state).When the ready state is achieved the
m_ResumeCond
is signalled and a waiting thread is released from suspension. But before it is allowed to exitpthread_cond_wait()
it must reaquire the lock onm_SuspendMutex
to make sure it is the only thread modifying the resources protected by the mutex.To make sure the above is done correctly in an atomic fashion (the unlock/suspend/resume/lock) must by done by
pthread_cond_wait()
.No.
As good as any other I suppose.