linux驱动程序中的并发控制-3(读写自旋锁)-45

Posted 杨斌并

tags:

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

读写自旋锁


  • 自旋锁不管读写,都只允许同时只有一个执行单元可以获取自旋锁,即便有多个单元同时读取临界区资源也会被锁住。
  • 读写自旋锁,将临界区的读写操作分开,多个执行单元可以同时获取一个读自旋锁,但是只能获取一个写自旋锁
  • 如果某个执行单元已经获取了一个读自旋锁,那么在获取写自旋锁时就是自旋等待读自旋锁的释放,读写不能同时进行

读写自旋锁的使用

  1. 定义读写自旋锁
rwlock_t lock;
  • rwlock_t 结构体 在头文件 #include<linux/rwlock.h>中
typedef struct {
	arch_rwlock_t raw_lock;
#ifdef CONFIG_GENERIC_LOCKBREAK
	unsigned int break_lock;
#endif
#ifdef CONFIG_DEBUG_SPINLOCK
	unsigned int magic, owner_cpu;
	void *owner;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
	struct lockdep_map dep_map;
#endif
} rwlock_t;
  1. 初始化读写自旋锁变量
  • 通过rwlock_init 宏初始化读写自旋锁变量
rwlock_init(&lock);
  1. 获取读写自旋
  • 获取读自旋锁
read_lock(&lock);
  • 获取写自旋锁
write_lock(&lock)

如果使用read lock 和write. lock 宏成功获取读写自旋锁,read_lock 和write_lock宏会立即返回。如果未获取读写自旋锁,read_lock 和write_lock 宏会被阻塞(在那自旋),直到可以获取读写自旋锁才返回。如果想不管是否成功获取读写自旋锁都立刻返回,可以使用read_ trylock 和write_ trylock 宏。

  1. 释放读写自旋锁
  • 释放读自旋锁
read_unlock(&lock);
  • 释放写自旋锁
write_unlock(&lock);
  1. 读写相关的api
函数描述
DEFINE RWLOCK(lock)定义和初始化读写自旋锁变量
void rwlock_init(rwlock_t *lock)初始化读写自旋锁变量
void read_lock(rwlock_t *lock)获取读自旋锁。如果无法获取读自旋锁,则不断自旋(循环)来检测读自旋锁是否可用
int read_trylock(rwlock_t *lock)获取读自旋锁。如果成功获取读自旋锁,则立刻返回非0 值,如果无法获取读自旋锁,则立刻返回0 (并不进行自旋,也就是说该宏不会被阻塞)
void read_unlock(rwlock_t *lock)释放读自旋锁
void write_lock(rwlock_t *lock)获取写自旋锁。如果无法获写读自旋锁,则不断自旋(循环)来检测写自旋锁是否可用
int write_trylock(rwlock_t *lock)获取写自旋锁。如果成功获取写自旋锁,则立刻返回非0 值,如果无法获取写自旋锁,则立刻返回0 (并不进行自旋,也就是说该宏不会被阻塞)
void write_unlock(rwlock_t *lock)释放写自旋锁
void read_lock_irq(rwlock_t *lock)获取读自旋锁,并禁止中断。相当于read. lock+ local irq disable
void read_unlock_irq(rwlock_t *lock)释放读自旋锁,并允许中断。相当于read. _unlock + local_irq_enable
void writc_lock_irq(rwlock_t *lock)获取写自旋锁,并禁止中断。相当于write_ lock + local_ irq disable
void write_unlock_irq(rwlock_t *lock)释放写自旋锁,并允许中断。相当于write_ unlock + local irq_ enable
void read_lock_bh(rwlock_t *lock)释放读自旋锁,并禁止底半部。相当于read_lock + local_bh_disable
void read_unlock_bh(rwlock_t *lock)释放读自旋锁,并允许底半部。相当于read_ lock + local bh_ enable
void write_lock_bh(rwlock_t *lock)释放写自旋锁,并禁止底半部。相当于write_lock + local_bh_disable
void write_ _unlock _bh(rwlock t *lock)释放写自旋锁,并允许底半部。相当于write_lock + local_bh_enable

实例代码

  • read_write_lock.c
#include<linux/module.h>
#include<linux/init.h>
#include<linux/kernel.h>
#include<linux/uaccess.h>
#include<linux/fs.h>
#include<linux/miscdevice.h>
#include<linux/rwlock.h>
#include<linux/spinlock.h>
#include<linux/delay.h>

#define DEVICE_NAME "rw_lock"

static  char  *data = "read\\n";
//定义读写锁
static  DEFINE_RWLOCK(rwlock);
//定义自旋锁
static  DEFINE_SPINLOCK(lock);
//rw  代表 读写锁  spin 代表
static char *lock_type = "rw";


static int spin_lock_open(struct inode *node,struct file *file){

    printk("spin_lock_open \\n");


    return 0;

}

static int spin_lock_release(struct inode *node,struct file *file){
    printk("spin_lock_release \\n");

    return 0;
}


static int spin_lock_read(struct file * file, char __user * buf, size_t size, loff_t * ppos){

    int data_size = strlen(data);
    struct timeval tv;

    if (copy_to_user(buf, (void *)data, data_size))
    {
        return -EINVAL;
    }
    //获取单前的毫秒值
    do_gettimeofday(&tv);
    printk("read:start sec: %ld\\n", tv.tv_sec);

    if (strcmp(lock_type, "rw")==0)
    {
        read_lock(&rwlock);
    }else if (strcmp(lock_type, "spin") == 0)
    {
        spin_lock(&lock);
    }

    do_gettimeofday(&tv);
    printk("read: end sec: %ld\\n", tv.tv_sec);

    //模拟写临界代码模拟代码运行过程,所以延迟5秒
    mdelay(10000);

    if (strcmp(lock_type, "rw")==0)
    {
        read_unlock(&rwlock);
        
    }else if (strcmp(lock_type, "spin")==0)
    {
        spin_unlock(&lock);
    }
    return data_size;
}

static int spin_lock_write(struct file *file, const char __user *buf, size_t size, loff_t * ppos){
    struct timeval tv;
    do_gettimeofday(&tv);
    printk("write: start sec:%d \\n", tv.tv_sec);

    if (strcmp(lock_type, "rw") == 0)
    {
        write_lock(&rwlock);
    }else if (strcmp(lock_type, "spin")==0)
    {
        spin_lock(&lock);
    }

    do_gettimeofday(&tv);
    printk("write: end sec: %ld \\n", tv.tv_sec);

    //模拟写临界代码模拟代码运行过程,所以延迟5秒
    mdelay(10000);
    if (strcmp(lock_type, "rw") == 0)
    {
        write_unlock(&rwlock);
    }else if (strcmp(lock_type, "spin") == 0)
    {
        spin_unlock(&lock);
    }

    return size;
}

static struct file_operations dev_fops={
    .owner = THIS_MODULE,
    .open = spin_lock_open,
    .release = spin_lock_release,
    .read = spin_lock_read,
    .write = spin_lock_write
};

static struct miscdevice misc={
    .minor=MISC_DYNAMIC_MINOR,
    .name=DEVICE_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");
    return ret;
}

static void demo_exit(void){
    printk("ademo_exit_success\\n");
    misc_deregister(&misc);
}
module_init(demo_init);
module_exit(demo_exit);
module_param(lock_type,charp ,S_IRUGO|S_IWUSR);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("binbing.Yang");
  • app.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

int main(int argc, char *argv[]){
    int handler=open("/dev/rw_lock",0);
    char buf[5];
    printf("handler : %d\\n",handler);
    if (handler > 0)
    {

        read(handler,buf,4);
        buf[4] = '\\0';
        printf("%s \\n", buf);
        
    }

    return 0;
}
  • build.sh 测试脚本
  • app 可执行文件在/data/local/tmp/ 目录
#!/system/bin/sh
cd /data/local/tmp/
pwd
./app &
./app &
./app &
echo abdc > /dev/rw_lock &
echo abdc > /dev/rw_lock &
echo abdc > /dev/rw_lock &
  • 多个可执行单元可以同时执行读的操作
  • 写的操作,必须一个执行完,释放掉锁在执行下一个获取到锁的执行单元

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

linux驱动程序中的并发控制-4(顺序自旋锁)-46

linux驱动程序中的并发控制-4(顺序自旋锁)-46

linux驱动程序中的并发控制-4(顺序自旋锁)-46

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

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

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