使用 pthread_cond_signal 优雅地终止线程被证明是有问题的

2024-05-30

我需要发射一堆线程,并希望优雅地将它们拉下来。

我正在尝试使用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如果没有线程等待,则不执行任何操作,因此可能某些线程不会收到信号,因此不知道退出。

我该如何克服这个。

M.

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



首先,您必须将谓词更改为

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

to

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

这是 pthreads 的事情,你必须警惕虚假唤醒 http://vladimir_prus.blogspot.com/2005/07/spurious-wakeups.html.

现在您可以将其更改为

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

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

因此,在您的拆卸函数中,将循环替换为:

pthread_cond_broadcast(&cond);

这应该确保所有线程都被唤醒,并且会看到finished set to true并退出。

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

另一种常见的模式是注入有害消息。有害消息只是您的线程可以识别的特殊消息,这意味着“停止”,您可以将与线程数量一样多的这些消息放入队列中。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 pthread_cond_signal 优雅地终止线程被证明是有问题的 的相关文章

  • 如何读取扩展文件属性/文件元数据

    因此 我按照教程使用 ASP net core 将文件 上传 到本地路径 这是代码 public IActionResult About IList
  • 使用Physics.Raycast 和Physics2D.Raycast 检测对象上的点击

    我的场景中有一个空的游戏对象 带有 2D 组件盒碰撞器 我将脚本附加到该游戏对象 void OnMouseDown Debug Log clic 但是当我点击我的游戏对象时 没有任何效果 你有什么想法 如何检测我的盒子碰撞器上的点击 使用光
  • Unix网络编程澄清

    我正在翻阅这本经典书籍Unix网络编程 https rads stackoverflow com amzn click com 0139498761 当我偶然发现这个程序时 第 6 8 节 第 179 180 页 include unp h
  • 如何检查QProcess是否正确执行?

    QProcess process sdcompare QString command sdcompare QStringList args sdcompare command sdcompare diff args sdcompare lt
  • 向 Nhibernate 发出 SQL 查询

    如何将此 SQL 查询发送给 Nhibernate SELECT Customer name FROM Company INNER JOIN Customer ON Company CompanyId Customer CompanyId
  • XamlReader.Load 在后台线程中。是否可以?

    WPF 应用程序具有从单独的文件加载用户控件的操作 使用XamlReader Load method StreamReader mysr new StreamReader pathToFile DependencyObject rootOb
  • 单元测试一起运行时失败,单独运行时通过

    所以我的单元测试遇到了一些问题 我不能只是将它们复制并粘贴到这里 但我会尽力而为 问题似乎是 如果我一项一项地运行测试 一切都会按预期进行 但如果我告诉它一起运行测试 则 1 5 将通过 TestMethod public void Obj
  • 使用 C 语言使用 strftime() 获取缩写时区

    我看过this https stackoverflow com questions 34408909 how to get abbreviated timezone and this https stackoverflow com ques
  • 关于在 Windows 上使用 WiFi Direct Api?

    我目前正在开发一个应用程序 我需要在其中创建链接 阅读 无线网络连接 在桌面应用程序 在 Windows 10 上 和平板电脑 Android 但无关紧要 之间 工作流程 按钮 gt 如果需要提升权限 gt 创建类似托管网络的 WiFi 网
  • 将 Excel 导入到 Datagridview

    我使用此代码打开 Excel 文件并将其保存在 DataGridView 中 string name Items string constr Provider Microsoft Jet OLEDB 4 0 Data Source Dial
  • 在一个字节中存储 4 个不同的值

    我有一个任务要做 但我不知道从哪里开始 我不期待也绝对不想要代码中的答案 我想要一些关于该怎么做的指导 因为我感到有点失落 将变量打包和解包到一个字节中 您需要在一个字节中存储 4 个不同的值 这些值为 NAME RANGE BITS en
  • 批量更新 SQL Server C#

    我有一个 270k 行的数据库 带有主键mid和一个名为value 我有一个包含中值和值的文本文件 现在我想更新表格 以便将每个值分配给正确的中间值 我当前的方法是从 C 读取文本文件 并为我读取的每一行更新表中的一行 必须有更快的方法来做
  • Visual Studio 中的测试单独成功,但一组失败

    当我在 Visual Studio 中单独运行测试时 它们都顺利通过 然而 当我同时运行所有这些时 有些通过 有些失败 我尝试在每个测试方法之间暂停 1 秒 但没有成功 有任何想法吗 在此先感谢您的帮助 你们可能有一些共享数据 检查正在使用
  • 如何对 Web Api 操作进行后调用?

    我创建了一个 Web API 操作 如下所示 HttpPost public void Load string siteName string providerName UserDetails userDetails implementat
  • C++ 密码屏蔽

    我正在编写一个代码来接收密码输入 下面是我的代码 程序运行良好 但问题是除了数字和字母字符之外的其他键也被读取 例如删除 插入等 我知道如何避免它吗 特q string pw char c while c 13 Loop until Ent
  • Process.Start() 方法在什么情况下返回 false?

    From MSDN https msdn microsoft com en us library e8zac0ca v vs 110 aspx 返回值 true 表示有新的进程资源 开始了 如果由 FileName 成员指定的进程资源 St
  • Server.MapPath - 给定的物理路径,预期的虚拟路径

    我正在使用这行代码 var files Directory GetFiles Server MapPath E ftproot sales 在文件夹中查找文件 但是我收到错误消息说 给定物理路径但虚拟路径 预期的 我对在 C 中使用 Sys
  • 线程和 fork()。我该如何处理呢? [复制]

    这个问题在这里已经有答案了 可能的重复 多线程程序中的fork https stackoverflow com questions 1235516 fork in multi threaded program 如果我有一个使用 fork 的
  • Linq-to-entities,在一个查询中获取结果+行数

    我已经看到了有关此事的多个问题 但它们已经有 2 年 或更长 的历史了 所以我想知道这方面是否有任何变化 基本思想是填充网格视图并创建自定义分页 所以 我还需要结果和行数 在 SQL 中 这将类似于 SELECT COUNT id Id N
  • 检查Windows控制台中是否按下了键[重复]

    这个问题在这里已经有答案了 可能的重复 C 控制台键盘事件 https stackoverflow com questions 2067893 c console keyboard events 我希望 Windows 控制台程序在按下某个

随机推荐