转自: http://blog.csdn.net/wealoong/article/details/8490654

Linux内核中,completion是一种简单的同步机制,标志"things may proceed"。

要使用completion,必须在文件中包含<linux/completion.h>,同时创建一个类型为struct completion的变量。

  1. 这个变量可以静态地声明和初始化:
  2. DECLARE_COMPLETION(my_comp);
  3. 或者动态初始化:
  4. struct completion my_comp;
  5. init_completion(&my_comp);

如果驱动程序要在执行后面操作之前等待某个过程的完成,它可以调用wait_for_completion ,以要完成的事件为参数:

  1. void wait_for_completion(struct completion *comp);

wait_for_completion等待在completion上。如果加了interruptible,就表示线程等待可被外部发来的信号打断;如果加了killable,就表示线程只可被kill信号打断;如果加了timeout,表示等待超出一定时间会自动结束等待,timeout的单位是系统所用的时间片jiffies(多为1ms)。

如果其它部分代码可以确定事件已经完成,可以调用下面两个函数之一来唤醒等待该事件的进程:

  1. void complete(struct completion *comp);
  2. void complete_all(struct completion *comp); /* Linux 2.5.x以上版本 */

前一个函数将只唤醒一个等待进程,而后一个函数唤醒等待该事件的所以进程。由于completion的实现方式,即使complete在wait_for_competion之前调用,也可以正常工作。
例如,在MD设备驱动程序实现中,有一个恢复线程md_recovery_thread。驱动程序通过md_register_thread和md_unregister_thread来注册和注销恢复线程。恢复线程的执行逻辑在md_thread函数中,大致如下:

  1. int md_thread(void * arg)
  2. {
  3. 线程初始化;
  4. while (运行) {
  5. 处理逻辑;
  6. 接收信号;
  7. }
  8. return 0;
  9. }

md_register_thread将创建一个恢复线程,它必须在线程真正初始化结束之后才能返回该线程的指针。因此,其逻辑是:

  1. mdk_thread_t *md_register_thread(void (*run) (void *), void *data, const char *name)
  2. {
  3. mdk_thread_t *thread;
  4. ……
  5. struct completion event;
  6. /* 为线程分配空间 */
  7. thread = (mdk_thread_t *) kmalloc (sizeof(mdk_thread_t), GFP_KERNEL);
  8. ……
  9. init_completion(&event);
  10. ……
  11. thread->event = &event;
  12. /* 创建内核线程 */
  13. ret = kernel_thread(md_thread, thread, 0);
  14. /* 等待线程初始化结束 */
  15. ……
  16. wait_for_completion(&event);
  17. /* 返回线程指针 */
  18. return thread;
  19. }

而md_unregister_thread通过向线程发送SIGKILL信号注销恢复线程,它也需要在线程真正退出后才能释放线程所占用的内存。因此,其逻辑是:

  1. void md_unregister_thread(mdk_thread_t *thread)
  2. {
  3. struct completion event;
  4. init_completion(&event);
  5. thread->event = &event;
  6. ……
  7. /* 向线程发送SIGKILL信号终止其运行 */
  8. md_interrupt_thread(thread);
  9. /* 等待线程退出 */
  10. wait_for_completion(&event);
  11. /* 释放线程所占用的内存 */
  12. kfree(thread);
  13. }

如果考虑completion,md_thread的逻辑是:

  1. int md_thread(void * arg)
  2. {
  3. 线程初始化;
  4. complete(thread->event);
  5. while (运行) {
  6. 处理逻辑;
  7. 接收信号;
  8. }
  9. complete(thread->event);
  10. return 0;
  11. }

需要说明的是,由于等待事件是在驱动程序和恢复线程中的一个共享资源,它必须是一个全局变量,或者如实现代码中,定义为一个局部变量,而将其指针放在恢复线程结构中。
typedef struct mdk_thread_s {
    ……
    struct completion *event;
    ……
} mdk_thread_t;

 
 

最新文章

  1. chorme浏览器调试Android设备
  2. sharepoint powershell 批量处理匿名访问
  3. Android Home键监听
  4. Java集合类学习-LinkedList, ArrayList, Stack, Queue, Vector
  5. 《java集合概述》
  6. Oracle过程及函数的参数模式,In、out、in out模式
  7. neutron用linux_bridge部署provider网络
  8. 【63测试20161111】【BFS】【DP】【字符串】
  9. -include和sinclude 作用
  10. ASP.NET C# 日期 时间 年 月 日 时 分 秒 格式及转换(转自happymagic的专栏)
  11. DZ!NT论坛 3.6.711删除用户各种错解决方案
  12. Careercup - Microsoft面试题 - 5120588943196160
  13. The source attachment does not contain the source for the file SignatureParser.class错误
  14. 249. Group Shifted Strings
  15. Windows性能计数器--磁盘性能分析Disk
  16. C++中#include的工作原理
  17. 敬请贤者:WEB、IOS开发(2年以上经验,大专);CTO、产品经理,运营专员 电商服装鞋饰买手(2年以上经验,服装或鞋类);体验店店长 (2年以上经验,服装或鞋类) 工作地点:丰台南苑路;有意者小窗QQ2211788980 - V2EX
  18. Filter和FilterChain具体的使用说明
  19. LaTeX新人30分钟从完全陌生到基本入门
  20. UI事务重叠引发的crash

热门文章

  1. STM8|STM32 看门狗使用
  2. pycharm 安装venv的依赖包
  3. VHD容量调整的方法(保存原有vhd)
  4. css3的apprearance属性(转)
  5. 原生的ajax(json)
  6. 重启OpenStack服务步骤
  7. POJ 2976 Dropping tests 01分数规划 模板
  8. Unity3D中的函数方法及解释
  9. 使用Java操作文本文件的方法详解
  10. 四、Hbase