8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

调用 pthread_cond_signal 而不锁定互斥锁

Sarin Jacob Sunny 3月前

68 0

我从某处读到,我们应该在调用 pthread_cond_signal 之前锁定互斥锁,并在调用它之后解锁互斥锁:pthread_cond_signal() 例程用于发出信号(或唤醒)另一个……

我在某处读到我们应该 在调用 互斥锁 pthread_cond_signal 并在调用它之后解锁互斥锁:

pthread_cond_signal() 例程用于向另一个正在等待条件变量的线程发送信号(或唤醒)。应在互斥锁锁定后调用此例程,并且必须解锁互斥锁,pthread_cond_wait() 例程才​​能完成。

在不锁定互斥锁的情况下 pthread_cond_signal pthread_cond_broadcast 不行吗

帖子版权声明 1、本帖标题:调用 pthread_cond_signal 而不锁定互斥锁
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由Sarin Jacob Sunny在本站《linux》版块原创发布, 转载请注明出处!
最新回复 (0)
  • 如果您没有在更改条件和信号的代码路径中锁定互斥锁,则可能会丢失唤醒。考虑以下两个过程:

    流程A:

    pthread_mutex_lock(&mutex);
    while (condition == FALSE)
        pthread_cond_wait(&cond, &mutex);
    pthread_mutex_unlock(&mutex);
    

    过程B(错误):

    condition = TRUE;
    pthread_cond_signal(&cond);
    

    然后考虑这种可能的指令交错,其中 condition 开始于 FALSE

    Process A                             Process B
    
    pthread_mutex_lock(&mutex);
    while (condition == FALSE)
    
                                          condition = TRUE;
                                          pthread_cond_signal(&cond);
    
    pthread_cond_wait(&cond, &mutex);
    

    现在 condition TRUE 等待条件变量 - 它错过了唤醒信号。如果我们改变进程 B 以锁定互斥锁:

    过程B(正确):

    pthread_mutex_lock(&mutex);
    condition = TRUE;
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mutex);
    

    ...那么上述情况就不会发生;唤醒将永远不会被错过。

    (请注意,您 实际上 可以 pthread_cond_signal() 本身移动到之后 pthread_mutex_unlock() ,但这可能会导致线程调度不太优化,并且由于更改条件本身,您必然已经在此代码路径中锁定了互斥锁)。

  • @Nemo:是的,在“正确”的路径中,pthread_signal_cond() 可以在互斥锁解锁后移动,尽管最好不要这样做。也许更正确的说法是,在调用 pthread_signal_cond() 时,您已经需要锁定互斥锁才能修改条件本身。

  • 不管怎样,似乎很难回答在信号之前还是之后解锁的问题。在信号之后解锁可确保低优先级线程无法从高优先级线程窃取事件,但如果不使用优先级,在信号之前解锁实际上会减少系统调用/上下文切换的次数并提高整体性能。

  • @R.. 你搞反了。在信号之前解锁会增加系统调用的数量并降低整体性能。如果你在解锁之前发出信号,实现就会知道信号不可能唤醒线程(因为任何在 cv 上被阻止的线程都需要互斥锁才能向前推进),从而允许它使用快速路径。如果你在解锁之后发出信号,解锁和信号都可以唤醒线程,这意味着它们都是昂贵的操作。

  • TVG 3月前 0 只看Ta
    引用 6

    此外,即使您可以将信号的工作推迟到互斥锁解锁时间,互斥锁也可以与无限多个 condvar 同时使用,因此互斥锁解锁将变成 O(n)而不是 O(1),这从实时属性的角度来看是极其不可取的。

  • @Alceste_:请参阅 POSIX 中的这段文字:“当线程等待条件变量时,如果已为 pthread_cond_timedwait() 或 pthread_cond_wait() 操作指定了特定互斥锁,则该互斥锁和条件变量之间会形成动态绑定,只要至少有一个线程被条件变量阻塞,该绑定就会一直有效。在此期间,任何线程尝试使用其他互斥锁等待该条件变量的效果都是不确定的。”

  • 根据本手册:

    pthread_cond_broadcast() 函数 pthread_cond_signal() 可由线程调用,无论它当前是否拥有线程在等待期间与条件变量关联的互斥锁但是 pthread_cond_wait() ,如果需要可预测的调度行为,则该互斥锁应由调用 pthread_cond_timedwait() pthread_cond_broadcast() pthread_cond_signal() .

    《使用 POSIX 线程编程 的作者)在 comp.programming.threads 上解释了 可预测调度行为 的含义 ,可 在此处 .

  • +1,感谢 Dave Butenhof 的邮件链接。我自己也一直对这个问题感到疑惑,现在我知道了……今天学到了一些重要的东西。谢谢。

  • 如果需要可预测的调度行为,则按所需顺序将语句放在一个线程中,或使用线程优先级。

  • caf,在您的示例代码中,进程 B 在 condition 没有先锁定互斥锁的情况下进行修改。如果进程 B 在修改期间只是锁定互斥锁,然后在调用之前仍然解锁互斥锁 pthread_cond_signal ,那么就不会出现问题 --- 我说得对吗?

    我直觉地认为 caf 的 立场 是正确的: pthread_cond_signal 在不拥有互斥锁的情况下进行调用是一个坏主意。但 caf 的 示例 实际上并不是支持这一立场的证据;它只是支持一个更弱(实际上是不言而喻的)立场的证据,即除非您先锁定了互斥锁,否则修改受互斥锁保护的共享状态是一个坏主意。

    有人可以提供一些示例代码吗?其中调用 pthread_cond_signal 后跟 pthread_mutex_unlock 产生正确的行为,但调用 pthread_mutex_unlock 后跟 pthread_cond_signal 产生不正确的行为?

  • 实际上,我认为我的问题与此问题重复,答案是“没问题,您完全可以在不拥有互斥锁的情况下调用 pthread_cond_signal。这不存在正确性问题。但在常见的实现中,您会错过 pthreads 内部的一个巧妙优化,因此最好在仍持有锁的情况下调用 pthread_cond_signal。\'

  • 这里有一个很好的场景:.com/a/6419626/1284631 请注意,它并没有声称行为不正确,它只是提出了一种行为可能不符合预期的情况。

  • 可以创建示例代码,其中在 pthread_mutex_unlock 之后调用 pthread_cond_signal 可能会导致唤醒丢失,因为信号被“错误”线程捕获,该线程在看到谓词的变化后被阻塞。这只有在同一个条件变量可用于多个谓词并且您不使用 pthread_cond_broadcast 时才会出现问题,无论如何,这是一种罕见且脆弱的模式。

返回
作者最近主题: