Reputation: 5452
In my program I have a daemon thread that waits for tasks and print them to a file. Its function is:
void * deamon(void *) {
while(true) {
pthread_mutex_lock(manager->getLock());
while(!manager->isPending()) {
if (manager->isClosing()) {
pthread_exit(NULL);
}
pthread_cond_wait(manager->getCond(), manager->getLock());
//check that condition if met - surprises may occur!
}
//WRITE TO FILE HERE
pthread_mutex_unlock(manager->getLock());
}
return NULL;
}
So as you can see the when there are no pending task the daemon waits for new ones. When I get a new one I push it to a data base in a different class (daemon is not in a class) and then send a signal as follows:
void Manager::pushNewTask(Task * task) {
pthread_mutex_lock(_lock);
map<int,Task *>::iterator it = _tasks->end();
_tasks->insert(it,make_pair(task->getId(),task));
// At the first time a signal is sent with no need
if (_tasks->size() == 1) {
_pending = true;
pthread_cond_signal(_cond); //SEND SIGNAL TO DAEMON THREAD
}
pthread_mutex_unlock(_lock);
}
Three questions:
daemon()
and pushNewTask()
use the same pthread_mutex_t
object - is that not a problem? When daemon goes to sleep (wait) it doesn't unlock the mutex.pthread_mutex_lock
? Maybe that only one thread can access either of them? When should I use different pthread_mutex_t objects
?Thanks
Upvotes: 0
Views: 1814
Reputation: 264331
1: Its not clear from the code here but both daemon() and pushNewTask() use the same pthread_mutex_t object - is that not a problem?
pthread_cond_wait(manager->getCond(), manager->getLock());
No this is not a problem. The call to pthread_cond_wait()
releases the lock and suspends the thread. When the condition variable is signaled. The thread re-aquires the lock and then returns from the call to pthread_cond_wait()
. So while the thread is running it will have the lock and while it is asleep the lock is released (note if another thread is holding the lock on the mutext the thread can not exit pthread_cond_wait()
).
2: What is the meaning that several functions are locked with the same pthread_mutex_lock? Maybe that only one thread can access either of them? When should I use different pthread_mutex_t objects?
No. You should always use the same mutex/condition variable pair. Also access to an object (in this case the Manager
object) is usually controlled by a single lock. This means that only the thread holding the lock can execute code in the manager object (thus only one thread at a time). Threads suspended on a 'condition variable` release the lock so other threads can work while they are suspended but must re-aquire the lock before they are allowed to execute code in the manager.
pthread_cond_wait(manager->getCond(), manager->getLock());
This is highly susceptible to race conditions. It should be written like this:
while(<No Tasks available>)
{
pthread_cond_wait(manager->getCond(), manager->getLock());
}
if (manager->isClosing()) {
pthread_exit(NULL);
}
This is a problem. The thread is dying while still holding a lock on the mutex. Before the thread dies it should release the mutex. Preferablly the mutex should be controlled via RAII so that its usage is exception safe and you can exit the thread by returning from the function rather than call pthread_exit().
Using pthread_exit() is like calling exit() in a normal application. This is not a good idea as automatic objects on the stack are not correctly destroyed. This can be a problem in C++ code thus the use of pthread_exit() is discouraged, instead you should let the thread die naturally by allowing it to return from the original function that initiated it. (PS do not throw an exception that unwinds a thread stack to the end. What pthreads does when a thread exits because of an exception is undefined (most systems I have seen this causes the application to terminate)).
Upvotes: 3