zoukankan      html  css  js  c++  java
  • 条件变量调用Signal的时候是否需要持有mutex

    Features of Mutexes and Condition Variables

    It had been suggested that the mutex acquisition and release be decoupled from condition wait. This was rejected because it is the combined nature of the operation that, in fact, facilitates realtime implementations. Those implementations can atomically move a high-priority thread between the condition variable and the mutex in a manner that is transparent to the caller. This can prevent extra context switches and provide more deterministic acquisition of a mutex when the waiting thread is signaled. Thus, fairness and priority issues can be dealt with directly by the scheduling discipline. Furthermore, the current condition wait operation matches existing practice.

    Scheduling Behavior of Mutexes and Condition Variables

    Synchronization primitives that attempt to interfere with scheduling policy by specifying an ordering rule are considered undesirable. Threads waiting on mutexes and condition variables are selected to proceed in an order dependent upon the scheduling policy rather than in some fixed order (for example, FIFO or priority). Thus, the scheduling policy determines which thread(s) are awakened and allowed to proceed.





    正文

    条件变量调用Signal的时候是否需要持有mutex

    通过分析不同的说法来确定

    The pthread_cond_broadcast() or pthread_cond_signal() functions may be called by a thread whether or not it currently owns the mutex that threads calling pthread_cond_wait() or pthread_cond_timedwait() have associated with the condition variable during their waits; however, if predictable scheduling behavior is required, then that mutex shall be locked by the thread calling pthread_cond_broadcast() or pthread_cond_signal().

    结论: 持有锁和不持有锁都可以, 但是, if predictable scheduling behavior is required, then that mutex shall be locked by the thread calling


    来自SO的一个回答

    If you do not lock the mutex in the codepath that changes the condition and signals, you can lose wakeups. Consider this pair of processes:

    Process A:

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

    Process B (incorrect):

    condition = TRUE;
    pthread_cond_signal(&cond);
    

    Then consider this possible interleaving of instructions, where condition starts out as FALSE:

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

    The condition is now TRUE, but Process A is stuck waiting on the condition variable - it missed the wakeup signal. If we alter Process B to lock the mutex:

    Process B (correct):

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

    ...then the above cannot occur; the wakeup will never be missed.

    (Note that you can actually move the pthread_cond_signal() itself after the pthread_mutex_unlock(), but this can result in less optimal scheduling of threads, and you've necessarily locked the mutex already in this code path due to changing the condition itself).

    in the "correct" path the pthread_signal_cond() can be moved after the mutex unlock, although it is probably better not to. It is perhaps more correct to say that at the point where you are calling pthread_signal_cond(), you will have already needed to have locked the mutex to modify the condition itself.

    在他的观点中, 两种顺序都可以, 但是signal持有锁更好

    而另一位回答者则说道

    1. Unlocking after ensures that a lower-priority thread won’t be able to steal the event from a higher-priority one, but if you’re not using priorities.
    2. Unlocking before the signal will actually reduce the number of system calls/context switches and improve overall performance.

    The notifying thread does not need to hold the lock on the same mutex as the one held by the waiting thread(s); in fact doing so is a pessimization, since the notified thread would immediately block again, waiting for the notifying thread to release the lock. However, some implementations (in particular many implementations of pthreads) recognize this situation and avoid this “hurry up and wait” scenario by transferring the waiting thread from the condition variable’s queue directly to the queue of the mutex within the notify call, without waking it up.
    Notifying while under the lock may nevertheless be necessary when precise scheduling of events is required, e.g. if the waiting thread would exit the program if the condition is satisfied, causing destruction of the notifying thread’s condition_variable. A spurious wakeup after mutex unlock but before notify would result in notify called on a destroyed object.

      也就是说, 在要求精确调度事件时,可能必须在处于锁下时通知,例如,在若满足条件则线程将退出程序,导致析构通知线程的 condition_variable 的情况下。互斥解锁之后,但在通知前的虚假唤醒可能导致通知在被销毁对象上调用。


    TIP: ALWAYS HOLD THE LOCK WHILE SIGNALING
    Although it is strictly not necessary in all cases, it is likely simplest and best to hold the lock while signaling when using condition variables. The example above shows a case where you must hold the lock for correctness; however, there are some other cases where it is likely OK not to, but probably is something you should avoid. Thus, for simplicity, hold the lock when calling signal.

    这也是我们学校的操作系统教材, 提出, 两种都可以, 但是为了方便最好持有锁调用signal, 这是最简单的办法


    Programming with POSIX Threads
    The problem (from the realtime side) with condition variables is that if you can signal/broadcast without holding the mutex, and any thread currently running can acquire an unlocked mutex and check a predicate without reference to the condition variable, then you can have an indirect priority inversion.


    The quoted statement simply indicates that if the producer continues to hold the mutex while waking consumer thread A, it will be able to run and block on the mutex in priority order before consumer thread B can acquire the mutex. (With wait morphing, the condition variable operation immediately transfers the highest priority waiter to the mutex with minimal overhead; but on any strict realtime implementation the act of unblocking a high priority thread will immediately preempt a lower priority thread and allow it to block on the mutex immediately.) Now, consumer thread B may not contend for the mutex before the unlock, in which case the “right thread” goes next, or it may contend anywhere during this sequence and be sorted into the proper priority order along with consumer thread A; in either case, the higher priority thread will have the first chance at the queue.
    That’s what “predictable scheduling behavior” means in this context. In more pragmatic terms, I’m pretty sure this means that someone on the realtime side of the virtual aisle thought it was a bad idea to recommend signaling “outside” the mutex, and the working group compromised by adding that statement, which was sufficient to ward off (or possibly to remove) a formal objection to the draft standard. This is how a lot of the text in the standard grew.

    总结

    • 如果realtime场景下在意调度行为predictable,实现精确调度, 最好signal之后再unlock。(predictable scheduling behavior)
    • 如果在应用层不在意thread优先级和执行顺序,那么可以先unlock。

    本文参考:
    https://blog.csdn.net/rsy56640/article/details/84953204

  • 相关阅读:
    Selenium-Xpath使用方法
    HTML基础之js
    HTML基础—DOM操作
    CSS基础知识总结二
    CSS基础知识总结之css样式引用的三种方式
    BZOJ 2329/2209 [HNOI2011]括号修复 (splay)
    BZOJ 1576 [USACO]安全路经Travel (树剖+线段树)
    BZOJ 2402 陶陶的难题II (01分数规划+树剖+线段树+凸包+二分)
    BZOJ 4044 Virus synthesis (回文自动机+dp)
    BZOJ 2342 [SHOI2011]双倍回文 (回文自动机)
  • 原文地址:https://www.cnblogs.com/Kimbing-Ng/p/12409797.html
Copyright © 2011-2022 走看看