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

Sca*_*ark 2 c++ multithreading mutex pthreads

我需要解雇一堆线程,并希望优雅地降低它们.

我正在尝试使用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;
}
Run Code Online (Sandbox Code Playgroud)

现在,这一切看起来都很精致(无论如何).

所以为了拆除我有这种方法的线程

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 );
    }
}
Run Code Online (Sandbox Code Playgroud)

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

我怎么过来这个.

M.

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


nos*_*nos 6

首先,你必须改变你的谓词

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

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

这是一个pthreads的事情,你必须保护自己免受虚假的唤醒.

现在你可以改变它

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

因为在那次检查之后,你已经测试了是否设置完成并退出,如果是这样,你所要做的就是发出所有线程的信号.

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

pthread_cond_broadcast(&cond);
Run Code Online (Sandbox Code Playgroud)

这应该确保所有线程都被唤醒,并且将看到finished设置为true和退出.

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

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

  • 如果他们正在忙着处理,他们已经被唤醒了,他们将在下一个循环中退出,因为它已经完成了.因为你的拆解()在你完成设置时持有互斥锁,所以你是安全的. (2认同)
  • 你应该保持锁定,直到你完成信号,我友好的男人页面说:解锁互斥锁并暂停条件变量是原子地完成的.因此,如果所有线程在发出条件信号之前总是获取互斥锁,则可以保证在线程锁定互斥锁的时间和它在条件变量上等待的时间之间不会发出信号(从而忽略).请参阅此处以供参考http://manpage.b0red.de/3thr+pthread_cond_signal (2认同)