优雅的线程终止与pthread_cond_signal证明有问题

时间:2010-02-23 12:16:50

标签: c++ multithreading pthreads mutex

我需要解雇一堆线程并且想要优雅地降低它们。

我正在尝试使用pthread_cond_signal / pthread_cond_wait来实现这一目标,但遇到了问题。

这是我的代码。首先是thread_main

static void *thrmain( void * arg )
{
    // acquire references to the cond var, mutex, finished flag and
    // message queue
    .....

    while( true )
    {
        pthread_mutex_lock( &lock );

        if ( msq.empty() )
        {
            // no messages so wait for one.
            pthread_cond_wait( &cnd, &lock );
        }

        // are we finished.
        if ( finished )
        {
            // finished so unlock the mutex and get out of here
            pthread_mutex_unlock( &lock );
            break;
        }

        if ( !msg.empty() )
        {
            // retrieve msg
            ....

            // finished with lock
            pthread_mutex_unlock( &lock );

            // perform action based on msg
            // outside of lock to avoid deadlock
        }
        else
        {
            // nothing to do so we're
            // finished with the lock.
            pthread_mutex_unlock( &lock );
        }
    }

    return 0;
}

现在,这一切看起来都很精致(对我而言)。

所以要拆掉线程我有这个方法

void teardown()
{
    // set the global finished var
    pthread_mutex_lock( &lock );
    finished = true;
    pthread_mutex_unlock( &lock );

    // loop over the threads, signalling them
    for ( int i = 0 ; i < threads.size() ; ++i )
    {
        // send a signal per thread to wake it up
        // and get it to check it's finished flag
        pthread_cond_signal( &cnd );
    }

    // need to loop over the threads and join them.
    for ( int i = 0 ; i < threads.size() ; ++i )
    {
        pthread_join( threads[ i ].tid, NULL );
    }
}

现在我知道pthread_cond_signal不能保证它唤醒哪个线程,所以我无法发信号并加入同一个循环。然而,这是一切都出错的地方。如果没有线程等待,pthread_cond_signal什么也不做,因此可能没有信号通知某些线程,因此不会知道退出。

我如何克服这个问题。

微米。

*****更新******* 请不要发布我应该使用pthread_cond_broadcast,因为它表现出完全相同的行为。它只会唤醒一个实际上正在等待cond var的线程。在此期间处理并且稍后再回来等待的任何线程都将错过信号并且将无视


4 个答案:

答案 0 :(得分:6)

首先,您必须从

更改谓词
if ( msq.empty() ) {
  // no messages so wait for one.
  pthread_cond_wait( &cnd, &lock );
}

while ( msq.empty() ) {
  // no messages so wait for one.
  pthread_cond_wait( &cnd, &lock );
}

这是一个pthreads的事情,你必须防范spurious wakeups

现在您可以将其更改为

while ( msq.empty()  && !finished) {
  // no messages so wait for one.
  pthread_cond_wait( &cnd, &lock );
}

在检查之后,您已经测试是否已设置完成并退出,如果是, 你所要做的就是发出所有线索的信号。

因此,在您的拆解功能中,将循环替换为:

pthread_cond_broadcast(&cond);

这应确保所有线程都被唤醒,并且会将finished设置为true并退出。

即使你的帖子没有卡在pthread_cond_wait中,这也是安全的。如果线程正在处理消息,它们将不会获得唤醒信号,但是它们将完成该处理,再次进入循环并看到finished == false并退出。

另一种常见的模式是注入毒药信息。有毒消息只是一个特殊的消息,你的线程可以识别它意味着“停止”,你可以在你的队列中放置尽可能多的消息。

答案 1 :(得分:0)

我猜你应该在调用pthread_cond_signal之后解锁互斥锁。另外,在获得互斥锁之后,请在进入条件等待之前检查“已完成”的条件。希望这有帮助!

答案 2 :(得分:-2)

您想使用pthread_cond_broadcast()代替pthread_cond_signal()。前者取消阻止所有线程在给定条件下等待。

答案 3 :(得分:-2)

我从未直接使用过pthreads(我更喜欢Boost.Threads),但我认为你应该调用pthread_cancel而不是pthread_cond_signal