0

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

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

谢谢

4

1 回答 1

3

1:这里的代码不清楚,但 daemon() 和 pushNewTask() 都使用相同的 pthread_mutex_t 对象 - 这不是问题吗?

pthread_cond_wait(manager->getCond(), manager->getLock());

不,这不是问题。调用pthread_cond_wait()释放锁并挂起线程。当条件变量发出信号时。线程重新获取锁,然后从对 的调用返回pthread_cond_wait()。因此,当线程正在运行时,它将拥有锁,而当它处于睡眠状态时,锁将被释放(注意,如果另一个线程在 mutext 上持有锁,则线程无法退出pthread_cond_wait())。

2:几个函数用同一个pthread_mutex_lock加锁是什么意思?也许只有一个线程可以访问它们中的任何一个?我什么时候应该使用不同的 pthread_mutex_t 对象?

不,您应该始终使用相同的互斥锁/条件变量对。此外,对对象(在本例中为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 会做什么是未定义的(我见过的大多数系统都会导致应用程序终止))。

于 2012-05-07T19:37:57.217 回答