通过条件变量唤醒的线程何时运行?

时间:2017-06-07 15:42:34

标签: c multithreading pthreads condition-variable

当我在按住相应的互斥锁时唤醒一个等待条件变量的线程时,我可以假设在我释放互斥锁之后以及其他任何人(包括我自己)可以再次锁定互斥锁之前,唤醒线程将会运行吗?或者我可以确定它将来会在某个时刻运行吗?

准确地说,假设我有以下功能。

bool taken = false;
int waiting = 0;

pthread_mutex_t m;   // properly initialised elsewhere
pthread_cond_t c;

void enter() {
    pthread_mutex_lock(&m);
    // Is `taken || (waiting == 0)` guaranteed here? 
    while (taken) {
        ++ waiting;
        pthread_cond_wait(&c, &m);
        -- waiting;
    }
    taken = true;
    pthread_mutex_unlock(&m);
}

void leave() {
    pthread_mutex_lock(&m);
    taken = false;
    if (waiting > 0) {
        pthread_cond_signal(&c);
    }
    pthread_mutex_unlock(&m);
}

(这是一个玩具示例,并不意味着有用。)

还假设所有线程都使用这些函数

enter()
// some work here
leave()

我是否可以在enter()中获取互斥锁后直接确定(请参阅代码中的注释),如果taken为false waiting必须为零? [在我看来应该是这种情况,因为唤醒线程将假设找到唤醒线程留下的状态(如果唤醒不是假的),否则这可能无法保证,但我做了在任何地方都找不到明确的措辞。]

我主要对(现代)Linux上的行为感兴趣,但当然知道这是否由POSIX定义也会引起关注。

注意:这可能已在another question中提出,但我希望我的更清楚。

t0执行pthread_cond_signal后,t1不再等待条件变量,但它也没有运行,因为t0仍然保留互斥锁;而t1正在等待互斥锁。线程t2也可能在enter()的开头等待互斥锁。现在t0释放互斥锁。 t1t2都在等待它。 t1是以特殊方式处理并保证获得它,还是t2可以获得它?

1 个答案:

答案 0 :(得分:1)

感谢您的评论,Carsten,清理了它。

不,请参阅此answer以获取更多参考。根据您的示例,t2可以在t1之前获取互斥锁,并且可能会出现竞争条件,从而导致意外结果。

重申,t0最初可能具有互斥锁并且位于行pthread_cond_wait(&c, &m);上的while循环中,并且互斥锁以原子方式释放referencet1可以调用leave()获取发送条件c的互斥锁,然后释放互斥锁。 t0将尝试通过--waiting获取现已释放的互斥锁来准备运行t1,但它可以由操作系统进行上下文切换。等待互斥锁的其他线程t2可以抓取并运行enter()导致意外结果,请参阅non-reentrantt2然后释放互斥锁。 t0可能会回退,只是看到价值已经发生变异。