【问题标题】:Does pthread_cond_wait lock the mutex und spurious wakeuppthread_cond_wait 是否锁定互斥锁和虚假唤醒
【发布时间】:2019-06-21 16:59:13
【问题描述】:

TL;DR

我有一个作业需要实现线程同步。在实施过程中,我担心pthread_cond_wait() 是否在虚假唤醒时也会锁定互斥锁,而不仅仅是在成功唤醒时。

任务

该任务是一个工人/交付问题,其中存在为工人提供订单的工作线程和管理线程。为此,有一个订单列表,工人从中获取订单,管理线程存放订单。订单列表是共享对象,需要同步。

到目前为止我的解决方案

我认为对于这个问题,我需要一个列表的监视器,以保护它免受空的访问或满时的存款。

void deposit_order(order_list* ol, order* o){
    pthread_mutex_lock(&(ol->mut_order_access));
    while(get_count(ol) >= MAX_ORDERS) {
        pthread_cond_wait(&(ol->cond_not_full), &(ol->mut_order_access));
    }

    ol->orders[ol->head] = o;
    ol->head = (ol->head+1)%MAX_ORDERS;
    ol->count++;
    
    pthread_cond_signal(&(ol->cond_not_empty));
    pthread_mutex_unlock(&(ol->mut_order_access));
}

order* get_order(order_list* ol) {
    pthread_mutex_lock(&(ol->mut_order_access));
    while(get_count(ol) <= 0) {
        pthread_cond_wait(&(ol->cond_not_empty), &(ol->mut_order_access));
    }
    order* o;
    
    o = ol->orders[ol->tail];
    ol->tail = (ol->tail+1)%MAX_ORDERS;
    ol->count--;
    
    pthread_cond_signal(&(ol->cond_not_full));
    pthread_mutex_unlock(&(ol->mut_order_access));
    return o;
}

我认为结构包含的内容并不重要,因为主题是如何同步访问。显然结构order_list 包含一个mutex 和两个条件变量来向另一个线程发出信号。因此,如果工作人员从列表中删除任务,它会向管理线程发出“非空”信号,以便它可以存入额外的订单。如果管理层存入订单,则向工作线程发出“非空”信号,因此一个线程可以从列表中删除订单。

我的担忧

到目前为止一切顺利,但现在我认为有一个事件,上述解决方案可能很关键,那就是“虚假唤醒”。从this thread 我了解到,如果相应的互斥锁(即mut_order_access)被另一个线程锁定,则线程无法虚假唤醒。但是,例如,如果列表中只有一个订单,以至于get_count(ol) &gt;= MAX_ORDERS 未完成,并且线程虚假地从等待中唤醒,检查条件并将其标记为不正确并跳出循环,该怎么办。然后另一个线程接收到信号并在前一个线程已经在临界区之后正常唤醒锁定互斥锁。所以现在两个线程都在关键区域,这将是一个失败。

问题

所以只有当线程在虚假唤醒时没有锁定互斥锁时才会发生上述情况,那么它是否在虚假唤醒时锁定互斥锁?

【问题讨论】:

    标签: c multithreading pthreads


    【解决方案1】:

    您对虚假唤醒条件的理解似乎不正确。虚假唤醒与互斥锁是否被另一个线程锁定无关。除非您有编程错误(破坏这些函数的约定、一般内存损坏或其他未定义的行为等),否则pthread_cond_wait 永远不会在没有调用线程持有(锁定)互斥锁的情况下返回。如果发生虚假唤醒,它仍然无法返回,直到重新获取互斥锁。即使在使用pthread_cancel 取消服务员的情况下,取消清理处理程序也无法开始运行,直到重新获取互斥锁。

    【讨论】:

    • 谢谢这正是我想知道的。我知道一个线程在 !successful 上获取互斥锁!当互斥锁被另一个线程获取时返回并且不能返回也不能虚假唤醒,但我想知道当它虚假唤醒并且互斥锁仍然解锁时它是否也获取互斥锁。
    【解决方案2】:

    一个函数可能会返回一个锁定或解锁的互斥体,并且让您无法区分差异,这将是完全无法使用的。你怎么可能知道是否解锁互斥锁?

    pthread_cond_wait 函数提供原子“解锁并等待”操作。它总是在返回之前重新获取互斥锁。当然,假设你不违反它的任何先决条件。

    您可以将其视为一个三步过程:

    1. 原子解锁并等待。
    2. 另一个线程发出信号/广播条件或存在虚假唤醒。
    3. 重新获取互斥锁

    只有当所有三个步骤都完成后,pthread_cond_wait 才会返回。当等待结束而没有另一个线程发送信号时,会发生虚假唤醒。

    【讨论】:

    • 当虚假唤醒发生时,我的观点是互斥锁仍然被唤醒的线程获取?
    • @Yastanub 如果不是,你能做什么?你不知道你是否持有互斥锁,所以不知道是否打电话给pthread_mutex_unlock。这样的缺陷会使pthread_cond_wait 完全无法使用。它还需要实现以某种方式检测唤醒是否是虚假的,或者不知道是否重新获取互斥锁,这完全违背了允许虚假唤醒的意义。
    猜你喜欢
    • 2017-04-21
    • 2011-10-11
    • 2010-11-22
    • 2011-09-12
    • 2013-02-02
    • 2012-01-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多