Linux内核的wake_up函数是否会引发竞态条件问题?
Linux内核__wake_up函数唤醒全部线程的竞态与资源争抢问题
你提到的__wake_up函数定义如下:
/** * __wake_up - wake up threads blocked on a waitqueue. * @wq_head: the waitqueue * @mode: which threads * @nr_exclusive: how many wake-one or wake-many threads to wake up * @key: is directly passed to the wakeup function * * If this function wakes up a task, it executes a full memory barrier before * accessing the task state. */ void __wake_up(struct wait_queue_head *wq_head, unsigned int mode, int nr_exclusive, void *key) { __wake_up_common_lock(wq_head, mode, nr_exclusive, 0, key); }
关于资源争抢
- 当你调用
__wake_up时传入nr_exclusive = 0,就会唤醒等待队列上的所有线程,这种场景确实会出现所有线程争抢同一共享资源的情况,也就是常说的惊群效应,会产生多余的上下文切换、锁竞争开销。 - 如果传入
nr_exclusive = 1,则只会唤醒1个标记了WQ_FLAG_EXCLUSIVE的独占等待线程,就能避免无意义的资源争抢。
关于竞态条件
- 竞态条件不会由
__wake_up的唤醒操作直接导致,是否出现竞态完全取决于上层访问共享资源的同步逻辑是否正确。 - 等待队列的标准使用范式要求访问共享资源时必须持有对应的互斥锁/自旋锁,示例逻辑如下:
// 等待线程侧逻辑 spin_lock(&resource_lock); while (资源不可用) { prepare_to_wait(&wait_queue, &wait_entry, TASK_INTERRUPTIBLE); spin_unlock(&resource_lock); schedule(); spin_lock(&resource_lock); } // 成功获取资源,执行业务逻辑 finish_wait(&wait_queue, &wait_entry); spin_unlock(&resource_lock);
- 只要遵循上述范式,哪怕同时唤醒所有等待线程,同一时间也只有一个线程能拿到锁访问资源,其余线程要么阻塞在锁上,要么拿到锁后发现资源已被占用,会自动回到等待状态,不会出现资源访问的竞态问题。
唤醒所有线程的适用场景
不是所有唤醒全部线程的操作都是不合理的,如果共享资源支持多线程并发访问(比如读多写少场景,写操作完成后所有读线程都可以同时访问资源),此时唤醒所有线程就是符合预期的设计,不会有额外的问题。
内容的提问来源于stack exchange,提问作者Shisui
相关产品推荐
相关产品推荐

