linux驱动程序中的并发控制-5(信号量(semaphore))-47
Posted 杨斌并
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux驱动程序中的并发控制-5(信号量(semaphore))-47相关的知识,希望对你有一定的参考价值。
信号量(semaphore)
- 信号量是用于保护临界区的一种常用方法,它的使用方式与自旋锁类似。
- 与自旋锁相同,只有得到信号量的进程才能执行临界区代码。
- 但与自旋锁不同的是,在未获取信号量时,进程不会像自旋锁-样原地打转,而是进入休眠等待状态。因此当信号量阻塞时消耗的系统资源(主要是CPU资源)并不多,也不会出现死机的现象。
信号量的使用
- 定义信号量(#include <linux/semaphore.h>)
struct semaphore sem;
- 初始化信号量
sema_init(&sem, 1);
函数原型
static inline void sema_init(struct semaphore *sem, int val)
{
static struct lock_class_key __key;
*sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val);
lockdep_init_map(&sem->lock.dep_map, "semaphore->lock", &__key, 0);
}
- sem semaphore 的结构体指针
- val 信号量的初始值,表示同时只能有val个进程访问共享资源
如果val等于1,表示同时只能有一个进程访问共享资源,如果有多于一个进程视图同时获取信号量,除了当前正在访问共享资源的进程外,其他的进程都将进入休眠状态,直到当前访问共享资源的进程释放信号量。如果让信号量和自旋锁起到同样的效果(共享数据同时只能由一个进程访问),val 参数的值应为1。如果val参数的值大于1,信号量就相当于一一个计数器。直到信号量为0,试图获取信号量才会被阻塞。.
- 获取信号量
extern void down(struct semaphore *sem);
extern int __must_check down_interruptible(struct semaphore *sem);
extern int __must_check down_trylock(struct semaphore *sem);
- down函数用于获取信号量sem,如果未能获取信号量,会导致当前进程休眠,中断仍然无法唤醒,因此不能在中断上下文使用。
- down_interruptible 函数与down函数类似,在未获得信号量时仍然可导致休眠,但在睡眠过程中可以被中断信号打断。打断时该函数返回非0值,正常结束(成功获取了信号量)返回0。一般在使用down_interruptible 函数时都会对其返回值进行判读,代码如下:
if (down_interruptible(&sem)) {
return -ERESTARTSYS;
}
- 使用down trylock 函数获取信号量时,不管是否成功获取信号量,该函数都会立即返回。如果成功获取信号量,返回0,否则返回非0值。down_trylock 函数不会休眠,可以用在中断上下文。
- 释放信号量
extern void up(struct semaphore *sem);
实例代码
信号量的初始值为1,当读取设备文件时,执行down函数成功获取信号量,并延长10秒来模拟执行临界区代码的过程,最后会执行up函数释放信号量。在10秒之内会向设备文件写入数据,这时会再执行down函数获取信号量,但down函数将会眠。直到5秒后,读设备文件时执行up函数释放信号量。写设备文件的write函数中的down函数才能被激活。示例的代码如下:
- semaphore_test.c
//
// rcu_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>
#include <linux/semaphore.h>
#include <linux/delay.h>
#define DEVICE_RCU_NAME "semaphore"
struct semaphore sem;
static ssize_t demo_read(struct file *file, char __user * buf, size_t count, loff_t *ppos){
struct timeval tv;
do_gettimeofday(&tv);
//输出单前的秒数
printk("semaphore read: start %ld\\n", tv.tv_sec);
//获取信号量
down(&sem);
//延迟10秒
mdelay(10000);
//释放信号量
up(&sem);
do_gettimeofday(&tv);
printk("semphore read: end %ld\\n", tv.tv_sec);
return 0;
}
static ssize_t demo_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos){
struct timeval tv;
do_gettimeofday(&tv);
printk("semphore write: start %ld \\n", tv.tv_sec);
down(&sem);
up(&sem);
do_gettimeofday(&tv);
printk("semphore write: end %ld\\n", tv.tv_sec);
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");
sema_init(&sem, 1);
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_AUTHOR("binbing.Yang");
- semaphore_test.sh
#!/system/bin/sh
cat /dev/semaphore
sleep 5
echo data > /dev/semaphore
输出 read end 和 write end 相差5秒,说明demo_write 函数中通过down函数休眠了5秒
以上是关于linux驱动程序中的并发控制-5(信号量(semaphore))-47的主要内容,如果未能解决你的问题,请参考以下文章