linux驱动程序中的并发控制-8(完成量(completion))-50
Posted 杨斌并
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux驱动程序中的并发控制-8(完成量(completion))-50相关的知识,希望对你有一定的参考价值。
完成量(completion)
- 完成量用于一个执行单元等待另一个执行单元执行完成某项工作。也就是说,如果在执行某段代码之前必须要执行另一段代码,就要使用完成量。
完成量(completion)使用
- 定义完成量
- 结构体(#include <linux/completion.h>)
static struct completion my_completion;
struct completion {
unsigned int done;
wait_queue_head_t wait;
};
其中done变量非常重要,该变量用于标识任务已经完成的次数。初始化后该变量值为0。后面会介绍如何使done变量加1或减1。
- 初始化完成量
init_completion(&my_completion);
//定义和初始化
DECLARE_COMPLETION(my_completion)
- 等待完成量
- wait_for_completion函数会根据completion. done变量的值决定是否等待一个完成量。该函数的定义如下:
void wait_for_completion(struct completion *c) ;
- 如果completion.done 变量的值为0,wait form completion会通过阻塞的方式等待一个completion的完成。并且每调用一次 wait_for_completion 函数completion.done 变量的值会减1,直到为0时被阻塞,继续等待completion的完成。
- 一个等待completion完成的函数是wait_ for_ completion interrupbible, 该函数的定义如下:
int wait_for_completion_interruptible (struct completion *c) ;
- wait_for_completion和wait_for_completion_interrupbible 的区别是wait_for_completion函数在等待completion完成时不能被中断打断,而wait_for_ completion_inferrupbible 函数在等待completion完成时可以被中断打断。
- 唤醒完成量
extern void complete(struct completion *);
extern void complete_all(struct completion *);
complete函数用于唤醒一个 等待的执行单元,complete_all 函数用于唤醒所有等待统一完成量的执行单元。调用compete 函数会使completion.done 变量的值加1, 而complete_all 函数会将completion.done变量值设为int的最大值,也就是2147483647。这也是为什么使用complete_all 函数可以唤醒所有completion的原因。只要被completion阻塞的执行单元不大于2147483647个,就可以都被唤醒。
实例
- completion_test.c
//
// completion_test.c
// seqlock_demo
//
// Created by lianfei on 2021/7/13.
//
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#define DEVICE_RCU_NAME "completion"
static struct completion my_completion;
static int completion_type = 0;
static ssize_t demo_read(struct file *file, char __user * buf, size_t count, loff_t *ppos){
printk("read start completion.done: %d\\n", my_completion.done);
wait_for_completion(&my_completion);
printk("read end completion.done: %d\\n", my_completion.done);
return 0;
}
static ssize_t demo_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos){
printk("write start completion.done: %d\\n", my_completion.done);
if (completion_type == 0) {
complete(&my_completion);
}else if (completion_type == 1){
complete_all(&my_completion);
}
printk("write end completion.done:%d\\n", my_completion.done);
return count;
}
static int demo_release(struct inode *node, struct file *file){
return 0;
}
static int demo_open(struct inode *node, struct file *file){
return 0;
}
static struct file_operations dev_fops={
.owner = THIS_MODULE,
.open = demo_open,
.release = demo_release,
.read = demo_read,
.write = demo_write
};
static struct miscdevice misc={
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_RCU_NAME,
.fops = &dev_fops
};
static int demo_init(void){
int ret=misc_register(&misc);
if(ret < 0 ){
printk("atomic_init is error\\n");
return -1;
}
printk("demo_init_success\\n");
init_completion(&my_completion);
return ret;
}
static void demo_exit(void){
printk("ademo_exit_success\\n");
misc_deregister(&misc);
}
module_init(demo_init);
module_exit(demo_exit);
MODULE_LICENSE("GPL");
module_param(completion_type, int, S_IRUGO|S_IWUSR);
MODULE_AUTHOR("binbing.Yang");
- 测试脚本
- completion_test.sh
#!/system/bin/sh
cat /dev/completion
echo data > /dev/completion
通过completion_type 模块参数可以设置completion驱动使用complete还是complete_all 函数唤醒完成量。当读取/dev/completion设备文件时,会调用demo_ read 函数,在该函数中调用了wait_for_completion函数等待,complete被唤醒。如果首先读取 /dev/completion 设备文件,demo_read函数将被阻塞,向/dev/completion 设备文件写入数据时,会调用demo_read 函数,在该函数中会根据completion_type模块参数的值使用complete或complete_all唤醒完成量。
以上是关于linux驱动程序中的并发控制-8(完成量(completion))-50的主要内容,如果未能解决你的问题,请参考以下文章
linux驱动程序中的并发控制-8(完成量(completion))-50