当前位置: 首页 > news >正文

complete_all 简介

complete_all 是 Linux 内核中用于线程同步的一种机制,属于 Completion API 的一部分。它的主要功能是唤醒等待在特定 struct completion 对象上的所有线程,并允许这些线程继续执行。以下是对 complete_all 的详细讲解:

功能

  • complete_all 唤醒等待队列中所有的线程,而不是像 complete 那样只唤醒一个线程。
  • 它会将 struct completion 中的 done 字段设置为一个高值(通常为 UINT_MAX),确保当前和未来的所有等待者都可以继续执行。

函数定义

void complete_all(struct completion *c);
  • 参数:
    • c: 指向一个 struct completion 对象的指针。
  • 作用: 唤醒所有在该 completion 上等待的线程。

使用场景

当多个线程需要等待某个事件完成时,调用 complete_all 可以同时唤醒所有等待线程。例如:

  • 线程 A 需要在某个条件满足后通知多个线程继续执行。
  • 用于广播式通知,确保所有依赖该事件的线程都能被唤醒。

实现原理

  1. 数据结构:

    • struct completion 是 Completion API 的核心结构,包含以下字段:
      struct completion {
          unsigned int done;          // 表示完成状态
          wait_queue_head_t wait;     // 等待队列
      };
      
    • done 字段表示完成状态,wait 是等待队列,用于存储等待该事件的线程。
  2. 工作机制:

    • 当调用 complete_all 时,它会将 done 设置为一个高值(如 UINT_MAX),并唤醒等待队列中的所有线程。
    • 这些被唤醒的线程会检查完成状态并继续执行。
  3. 注意事项:

    • 如果需要重复使用同一个 completion 对象,必须在调用 complete_all 后使用 reinit_completion() 对其重新初始化。
    • 多次调用 complete_all 是错误操作,因为它会破坏同步逻辑。

示例代码

以下代码展示了如何使用 complete_all

#include <linux/completion.h>
#include <linux/kthread.h>
#include <linux/module.h>

static struct task_struct *thread1, *thread2;
static struct completion my_completion;

static int thread_func(void *data) {
    printk("Thread %s waiting for completion...\n", current->comm);
    wait_for_completion(&my_completion);
    printk("Thread %s resumed after completion!\n", current->comm);
    return 0;
}

static int __init my_module_init(void) {
    init_completion(&my_completion);

    thread1 = kthread_run(thread_func, NULL, "thread1");
    thread2 = kthread_run(thread_func, NULL, "thread2");

    msleep(1000); // 模拟一些操作
    printk("Signaling all threads to continue...\n");
    complete_all(&my_completion);

    return 0;
}

static void __exit my_module_exit(void) {
    if (thread1)
        kthread_stop(thread1);
    if (thread2)
        kthread_stop(thread2);
}

module_init(my_module_init);
module_exit(my_module_exit);

MODULE_LICENSE("GPL");

说明

  1. 初始化了一个 completion 对象。
  2. 两个内核线程分别调用了 wait_for_completion(),进入等待状态。
  3. 主线程调用了 complete_all(),唤醒了所有等待的线程。

注意事项

  • 如果只需要唤醒一个线程,应使用 complete() 而非 complete_all()
  • 在中断上下文或原子上下文中调用是安全的,因为内部使用了自旋锁来保护数据结构。
  • 使用后若需重复利用同一对象,必须重新初始化,例如:
    reinit_completion(&my_completion);
    

总结

  • 特点: 轻量级、简单、高效,用于多线程间同步。
  • 适用场景: 多个线程需要同时被通知某一事件完成时。
  • 局限性: 调用后需重新初始化才能重复使用。

Citations:
[1] https://docs.kernel.org/translations/zh_CN/scheduler/completion.html
[2] https://developer.aliyun.com/article/375278
[3] https://www.cnblogs.com/zongfanstudy/p/13438211.html
[4] https://www.cnblogs.com/zhuyp1015/archive/2012/06/13/2548458.html
[5] https://stxinu.blogspot.com/2018/07/completion.html
[6] https://blog.csdn.net/weixin_29031161/article/details/117274948
[7] https://blog.csdn.net/tiantao2012/article/details/78810797
[8] http://www.deansys.com/doc/ldd3/ch05s04.html

相关文章:

  • 面试真题 | 招银 C++
  • DeepSeek的API密钥怎么使用
  • 【触想智能】工业显示器和普通显示器的区别以及工业显示器的主要应用领域分析
  • Neo4j集群学习
  • C#使用文件读写操作实现仙剑五前传称号存档修改
  • 工作一个月的经历和总结
  • Unity学习part3
  • 云计算——AWS Solutions Architect – Associate(saa)7.放置群组
  • 【LeetCode Hot100 普通数组】最大子数组和、合并区间、旋转数组、除自身以外数组的乘积、缺失的第一个正整数
  • 【Black Mesa】黑山起源用服务器开服多人联机教程
  • 2025年2月15日(虚拟环境-deepseek)
  • 什么是BlockingQueue?什么是阻塞队列?它的特点是什么?阻塞队列的生产方法和消费方法有什么?
  • 最佳的出牌方法
  • PbootCMS增加可允许上传文件类型,例如webp、mov等文件格式扩展
  • [小M全新力作-修稿]PFC_LLC电源设计全攻略:从原理学习到SIMULINK仿真到EDA板实战,再到实物电源调试
  • 什么是元学习?
  • 算法思考:非0整数除法
  • 建造者模式构建对象
  • 电解电容的参数指标
  • 高频更新字段问题思路
  • AG600“鲲龙”批生产首架机完成生产试飞
  • 上海交大曾小勤:科技传播不应停留于知识搬运,要做科学思维的播种机
  • 首次带人形机器人走科技节红毯,傅利叶顾捷:机器人行业没包袱,很多事都能从零开始
  • 女生“生理期请病假要脱裤子证明”?高校回应:视频经处理后有失真等问题
  • 专访|《内沙》导演杨弋枢:挽留终将失去的美好
  • 上海一保租房社区亮相,首批546套房源可拎包入住