在cpp中使用pthread_mutex_t

时间:2012-05-07 17:18:37

标签: c++ locking pthreads mutex

在我的程序中,我有一个守护程序线程,它等待任务并将它们打印到文件中。 它的功能是:

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);
}

三个问题:

  1. 此处的代码不清楚,但daemon()pushNewTask()使用相同的pthread_mutex_t对象 - 这不是问题吗?当守护进程进入休眠状态(等待)时,它不会解锁互斥锁。
  2. 使用相同的pthread_mutex_lock锁定多个函数的含义是什么?也许只有一个线程可以访问其中任何一个?我什么时候应该使用不同的pthread_mutex_t objects
  3. 由于

1 个答案:

答案 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());
}

请参阅:Thread Wait For Parent

错误:

        if (manager->isClosing()) {
            pthread_exit(NULL);
        }

这是一个问题。线程正在死亡,同时仍然锁定互斥锁。在线程死亡之前,它应该释放互斥锁。优选地,应该通过RAII控制互斥锁,以便它的使用是异常安全的,你可以通过从函数返回而不是调用pthread_exit()来退出线程。

使用pthread_exit()就像在普通应用程序中调用exit()一样。这不是一个好主意,因为堆栈上的自动对象没有被正确销毁。这可能是C ++代码中的一个问题,因此不鼓励使用pthread_exit(),而应该让线程自然地从启动它的原始函数返回。 (PS不会抛出一个将线程堆栈展开到最后的异常。当线程因异常而退出时,pthreads的作用是未定义的(大多数系统我看到这会导致应用程序终止)。