linux驱动程序中的并发控制-3(读写自旋锁)-45
Posted 杨斌并
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux驱动程序中的并发控制-3(读写自旋锁)-45相关的知识,希望对你有一定的参考价值。
读写自旋锁
- 自旋锁不管读写,都只允许同时只有一个执行单元可以获取自旋锁,即便有多个单元同时读取临界区资源也会被锁住。
- 读写自旋锁,将临界区的读写操作分开,多个执行单元可以同时获取一个读自旋锁,但是只能获取一个写自旋锁
- 如果某个执行单元已经获取了一个读自旋锁,那么在获取写自旋锁时就是自旋等待读自旋锁的释放,读写不能同时进行
读写自旋锁的使用
- 定义读写自旋锁
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;
- 初始化读写自旋锁变量
- 通过rwlock_init 宏初始化读写自旋锁变量
rwlock_init(&lock);
- 获取读写自旋
- 获取读自旋锁
read_lock(&lock);
- 获取写自旋锁
write_lock(&lock)
如果使用read lock 和write. lock 宏成功获取读写自旋锁,read_lock 和write_lock宏会立即返回。如果未获取读写自旋锁,read_lock 和write_lock 宏会被阻塞(在那自旋),直到可以获取读写自旋锁才返回。如果想不管是否成功获取读写自旋锁都立刻返回,可以使用read_ trylock 和write_ trylock 宏。
- 释放读写自旋锁
- 释放读自旋锁
read_unlock(&lock);
- 释放写自旋锁
write_unlock(&lock);
- 读写相关的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的主要内容,如果未能解决你的问题,请参考以下文章