前言
本文主要介绍linux内核同步机制中的完成量,及其使用实例。
一、什么是完成量
完成量(completion)是Linux系统提供的一种比信号量更好的同步机制,是对信号量的一种补充;它用于一个执行单元等待另一个执行单元完成某事;使用完成量等待时,调用进程是以睡眠方式进行等待的,不是忙等待。
二、完成量相关的数据结构和函数接口
1. 完成量相关的数据结构
- struct completion
- struct completion代表的就是一个完成量,其在内核源码中的linux/completion.h中定义。如下图所示为struct completion的数据结构定义
2. 完成量相关的函数接口
- 初始化完成量
init_completion(&my_completion) //初始化完成量my_completion
DECLARE_COMPLETION(my_completion); //定义和初始化完成量my_completion的快捷方式
说明:
以下两种方式是等效的,都实现了定义和初始化完成量my_completion的功能
- 动态方式
struct completion my_completion; //定义完成量my_completion
init_completion(&my_completion); //初始化完成量my_completion - 静态方式
DECLARE_COMPLETION(my_completion); //定义和初始化完成量my_completion
- 等待完成量
wait_for_completion(struct completion* complete)
该函数会阻塞调用进程, 如果所等待的完成量没有被唤醒,那就一直阻塞下去,而且不会被信号打断
wait_for_completion_interruptible(struct completion* complete)
该函数等待一个完成量被唤醒;但是它可以被外部信号打断
wait_for_completion_timeout(struct completion* complete, unsigned long timeout)
该函数等待一个完成量被唤醒;该函数会阻塞调用进程,如果所等待的完成量没有被唤醒,调用进程也不会一直阻塞下去,而是等待一个指定的超时时间timeout,当超时时间到达时,如果所等待的完成量仍然没有被唤醒,那就返回;并且超时时间timeout以系统的时钟滴答次数jiffies来计算;
try_wait_for_completion(struct completion* complete)
该函数尝试等待一个完成量被唤醒;不管所等待的完成量是否被唤醒,该函数都会立即返回
completion_done(struct completion* complete)
该函数用于检查是否有执行单元阻塞在完成量complete上(是否已经完成),返回0,表示有执行单元被完成量complete阻塞;相当于wait_for_completion_timeout()中的timeout=0;
说明:
- complete->done的值永远大于等于0;
- 调用wait_for_completion函数时,如果complete->done的值等于0,那么当前线程会进入睡眠。如果此时complete->done的值大于0,那么wait_for_completion()函数会将complete->done的值减1,然后继续向下执行;
- wait_for_completion()函数会执行一个不会被信号中断的等待。如果调用这个函数之后,没有一个线程完成这个完成量,那么执行wait_for_completion()函数的线程会一直等待下去,线程将不可以退出;
- 唤醒完成量
complete(struct completion* complete)
该函数只唤醒一个正在等待完成量complete的执行单元
complete_all()
该函数唤醒所有正在等待同一个完成量complete的执行单元
说明:
- complete函数会将complete->done的值加1,然后唤醒complete->wait中的一个线程;
- complete_all函数会将complete->done的值加1,然后唤醒complete->wait中的所有线程;
三、完成量的使用实例
以下代码实现了一个内核线程调用wait_for_completion()被阻塞住,另一个内核线程调用complete()唤醒之前被阻塞的线程的功能
- complete_demo.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/kthread.h>
#include <linux