在我的程序中,我有一个守护程序线程,它等待任务并将它们打印到文件中。 它的功能是:
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;
}
因此,您可以看到守护进程等待新进程时没有待处理任务。 当我得到一个新的时候,我将它推送到另一个类中的数据库(守护进程不在类中),然后发送如下信号:
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);
}
三个问题:
daemon()
和pushNewTask()
使用相同的pthread_mutex_t
对象 - 这不是问题吗?当守护进程进入休眠状态(等待)时,它不会解锁互斥锁。pthread_mutex_lock
锁定多个函数的含义是什么?也许只有一个线程可以访问其中任何一个?我什么时候应该使用不同的pthread_mutex_t objects
?由于
答案 0 :(得分:3)
1:这里的代码不清楚,但daemon()和pushNewTask()都使用相同的pthread_mutex_t对象 - 这不是问题吗?
pthread_cond_wait(manager->getCond(), manager->getLock());
不,这不是问题。对pthread_cond_wait()
的调用释放锁并挂起线程。当条件变量发出信号时。线程重新获取锁,然后从调用返回pthread_cond_wait()
。因此,当线程正在运行时,它将具有锁定,当它处于睡眠状态时,锁定被释放(注意,如果另一个线程正在保持锁定,则线程无法退出pthread_cond_wait()
)。
2:使用相同的pthread_mutex_lock锁定多个函数的含义是什么?也许只有一个线程可以访问其中任何一个?我什么时候应该使用不同的pthread_mutex_t对象?
没有。您应始终使用相同的互斥/条件变量对。访问对象(在本例中为Manager
对象)通常也由单个锁控制。这意味着只有持有锁的线程才能在manager对象中执行代码(因此一次只能执行一个线程)。挂起在'条件变量'上的线程释放锁定,以便其他线程在挂起时可以工作,但必须重新获取锁定才能允许它们在管理器中执行代码。
pthread_cond_wait(manager->getCond(), manager->getLock());
这非常容易受到竞争条件的影响。它应该写成这样:
while(<No Tasks available>)
{
pthread_cond_wait(manager->getCond(), manager->getLock());
}
if (manager->isClosing()) {
pthread_exit(NULL);
}
这是一个问题。线程正在死亡,同时仍然锁定互斥锁。在线程死亡之前,它应该释放互斥锁。优选地,应该通过RAII控制互斥锁,以便它的使用是异常安全的,你可以通过从函数返回而不是调用pthread_exit()来退出线程。
使用pthread_exit()就像在普通应用程序中调用exit()一样。这不是一个好主意,因为堆栈上的自动对象没有被正确销毁。这可能是C ++代码中的一个问题,因此不鼓励使用pthread_exit(),而应该让线程自然地从启动它的原始函数返回。 (PS不会抛出一个将线程堆栈展开到最后的异常。当线程因异常而退出时,pthreads的作用是未定义的(大多数系统我看到这会导致应用程序终止)。