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

Posted 杨斌并

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux驱动程序中的并发控制-6(读写信号量)-48相关的知识,希望对你有一定的参考价值。

读写信号量


  • 读写信号量和信号量的关系与读写自旋锁和自旋锁的关系类似。
  • 读信号量和写信号量是互斥的,但允许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函数就会被阻塞(由于读信号量未被释放)。

以上是关于linux驱动程序中的并发控制-6(读写信号量)-48的主要内容,如果未能解决你的问题,请参考以下文章

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

Linux设备驱动之并发控制

Linux并发与同步专题 信号量

Linux 设备驱动的并发控制 学习笔记

Linux驱动设备中的并发控制

linux驱动程序中的并发控制-5(信号量(semaphore))-47