linux驱动程序中的并发控制-6(读写信号量)-48

本文详细介绍了Linux内核中的读写信号量机制,它允许多个读取者同时访问资源,而写入者独占资源。通过示例代码展示了如何在设备驱动中使用读写信号量,确保并发访问的正确性和效率。同时,提供了一个测试脚本来模拟读写操作,以直观地展示读写信号量的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

读写信号量


  • 读写信号量和信号量的关系与读写自旋锁和自旋锁的关系类似。
  • 读信号量和写信号量是互斥的,但允许N个读执行单元同时访问共享资源(同时获取读信号量),而最多只允许有一个写单元获取写信号量。
  • 读写信号量相对于信号量更宽松,对于读多写少的情况会明显提高程序的执
    行效率。

读写信号量的使用

  1. 定义和初始化读写信号量
  • rw_semaphore 结构体(#include <linux/rwsem.h>)
struct rw_semaphore {
	long count;
	struct list_head wait_list;
	raw_spinlock_t wait_lock;
#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
	struct optimistic_spin_queue osq; /* spinner MCS lock */
	/*
	 * Write owner. Used as a speculative check to see
	 * if the owner is running on the cpu.
	 */
	struct task_struct *owner;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
	struct lockdep_map	dep_map;
#endif
};
  • 定义和初始化
struct rw_semaphore rw_sem;
init_rwsem(&rw_sem);
  1. 获取信号量
extern void down_write(struct rw_semaphore *sem);
extern int down_write_trylock(struct rw_semaphore *sem);
  • down_read函数用于获取读信号量,如果无法获取读信号量则会休眠。
  • down_read_trylock 函数不管是否能获取读信号量都会立即返回。如果成功获取读信号量则返回1,否则返回0。
  1. 获取写信号量
extern void up_write(struct rw_semaphore *sem);
extern void downgrade_write(struct rw_semaphore *sem);
  • down_write 函数用于获取写信号量,如果无法获取写信号量则会休眠。
  • down_write_trylock 函数不管是否能获取写信号量都会立即返回。如果成功获取写信号量则返回1,否则返回0。

实例

  • rw_semaphore_test.c
//
//  semaphore_rw_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/delay.h>
struct rw_semaphore rw_sem;

#define DEVICE_RCU_NAME "rw_semaphore"

static ssize_t demo_read(struct file *file, char __user * buf, size_t count, loff_t *ppos){
    
    struct timeval tv;
    
    do_gettimeofday(&tv);
    printk("rw_semaphore read: start %ld\n", tv.tv_sec);
    
    //获取读型号量
    down_read(&rw_sem);
    printk("rw_semaphore read: end %ld\n", tv.tv_sec);
    mdelay(10000);
    up_read(&rw_sem);
    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("write: start %ld \n", tv.tv_sec);
    down_write(&rw_sem);
    do_gettimeofday(&tv);
    printk("write: end %ld \n", tv.tv_sec);
    up_write(&rw_sem);
    
    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_rwsem(&rw_sem);
    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");
  • 测试脚本
  • rw_semaphore_test.sh
#!/system/bin/sh

cat /dev/rw_semaphore &
cat /dev/rw_semaphore &
cat /dev/rw_semaphore &
sleep 5
echo abcd > /dev/rw_semaphore

通过对设备文件的读写,演示如何使用读写信号量保护临界区的代码。在读设备文件时调用的demo_ read函数中使用了down_ read 函数获取读信号量,并且使用mdelay函数延迟5秒.来模拟读临界区代码的执行过程。在向设备文件写入数据时调用的demowrite函数中使用了down_ write 函数获取写信号量。从这一点可以看 出,多次调用demo read函数并不会被阻塞,但调用demo_read函数后再调用demo_write函数就会被阻塞(由于读信号量未被释放)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值