定义在头文件linux/rwsem.h或linux/rwsem-spinlock.h中
读写信号量与信号量之间的关系,类似于读写自旋锁与自旋锁之间的关系;读写信号量可能会引起进程阻塞,但是它允许N个读执行单元同时访问共享资源,而最多只允许有一个写执行单元访问共享资源;因此,读写信号量是一种相对放宽条件的、粒度稍大于信号量的互斥机制;
备注:信号量不允许任何操作之间有并发,即:读操作与读操作之间、读操作与写操作之间、写操作与写操作之间,都不允许并发;而读写信号量则只允许读操作与读操作之间可以并发,但不允许读操作与写操作之间的并发,也不允许写操作与写操作之间的并发;
1).定义并初始化读写信号量:
struct rw_semaphore rw_sem; //定义读写信号量
void init_rwsem(struct rw_semaphore* rw_sem); //初始化读写信号量
2).获取和释放读信号量:
void down_read(struct rw_semaphore* rw_sem); //获取读信号量
int down_read_trylock(struct rw_semaphore* rw_sem); //尝试获取读信号量
void up_read(struct rw_semaphore* rw_sem); //释放读信号量
3).获取和释放写信号量:
void down_write(struct rw_semaphore* rw_sem); //获取写信号量
int down_write_trylock(struct rw_semaphore* rw_sem);//尝试获取写信号量
void up_write(struct rw_semaphore* rw_sem); //释放写信号量
4).读写信号量的使用模式:
rw_semaphore sem; //定义读写信号量
init_rwsem(&sem); //初始化读写信号量
down_read(&sem); //读时获取信号量
...... //临界区代码
up_read(&sem); //读时释放信号量
down_write(&sem); //写时获取信号量
...... //临界区代码
up_write(&sem); //写时释放信号量
5).读写信号量降级:
void downgrade_write(struct rw_semaphore* sem);
该函数用于把写者降级为读者,有时,这是必要的.因为写者是互斥的、排它的,因此在写者保护读写信号量期间,任何读者或写者都将无法访问该信号量所保护的共享资源,对于那些当前条件下不需要写操作的访问者,降级为写者,将使得等待访问的读者能够立即访问,从而增加了并发性,提高了效率;
例子:
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/jiffies.h>
#include <linux/delay.h>
//这三个头文件与内核线程的使用有关;
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/err.h>
//读写信号量相关
//#include <linux/rwsem.h>
#include <linux/rwsem-spinlock.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("*************");
MODULE_VERSION("2.6.35.000");
static int sleep_time = (1*10*HZ);
static int shared_res = 0;
//STEP1:定义信号量
struct rw_semaphore my_rw_sem;
//STEP5:实现线程函数
static int thread_process1(void* param)
{
//int val = 0, ret = 0;
while(1)
{
set_current_state(TASK_UNINTERRUPTIBLE);
if(kthread_should_stop())
{
printk("kernel thread '%s' should stop;file:%s;line:%d\n", __FUNCTION__, __FILE__, __LINE__);
break;
}
//STEP3:对临界区加锁
down_write(&my_rw_sem);
shared_res++;
//STEP4:对临界区解锁
up_write(&my_rw_sem);
mdelay(sleep_time);
}
return 12;
};
static int thread_process2(void* param)
{
//int val = 0, ret = 0;
while(1)
{
set_current_state(TASK_UNINTERRUPTIBLE);
if(kthread_should_stop())
{
printk("kernel thread '%s' should stop;file:%s;line:%d\n", __FUNCTION__, __FILE__, __LINE__);
break;
}
//STEP3:对临界区加锁
down_write(&my_rw_sem);
shared_res++;
//STEP4:对临界区解锁
up_write(&my_rw_sem);
msleep(sleep_time);
}
return 34;
};
static int thread_process3(void* param)
{
int val = 0;//, ret = 0;
while(1)
{
set_current_state(TASK_UNINTERRUPTIBLE);
if(kthread_should_stop())
{
printk("kernel thread '%s' should stop;file:%s;line:%d\n", __FUNCTION__, __FILE__, __LINE__);
break;
}
//STEP3:对临界区加锁
down_read(&my_rw_sem);
val = shared_res;
printk("%s: shared resource = %d;\n%s", __FUNCTION__, val, ((val % 3) ? "" : "\n"));
//STEP4:对临界区解锁
up_read(&my_rw_sem);
msleep(sleep_time);
}
return 56;
};
static int thread_process4(void* param)
{
int val = 0;//, ret = 0;
while(1)
{
set_current_state(TASK_UNINTERRUPTIBLE);
if(kthread_should_stop())
{
printk("kernel thread '%s' should stop;file:%s;line:%d\n", __FUNCTION__, __FILE__, __LINE__);
break;
}
//STEP3:对临界区加锁
down_read(&my_rw_sem);
val = shared_res;
printk("%s: shared resource = %d;\n%s", __FUNCTION__, val, ((val % 3) ? "" : "\n"));
//STEP4:对临界区解锁
up_read(&my_rw_sem);
msleep(sleep_time);
}
return 78;
};
static struct task_struct* my_thread1 = NULL;
static struct task_struct* my_thread2 = NULL;
static struct task_struct* my_thread3 = NULL;
static struct task_struct* my_thread4 = NULL;
static int __init study_init(void)
{
int err = 0;
printk("%s\n", __PRETTY_FUNCTION__);
//STEP2:初始化读写信号量
init_rwsem(&my_rw_sem);
printk("init rw semaphore ok\n");
my_thread1 = kthread_create(thread_process1, NULL, "my_thread1");
if(IS_ERR(my_thread1))
{
err = PTR_ERR(my_thread1);
my_thread1 = NULL;
printk(KERN_ERR "unable to start kernel thread1:%d\n", err);
return err;
}
my_thread2 = kthread_create(thread_process2, NULL, "my_thread2");
if(IS_ERR(my_thread2))
{
err = PTR_ERR(my_thread2);
my_thread2 = NULL;
printk(KERN_ERR "unable to start kernel thread2:%d\n", err);
return err;
}
my_thread3 = kthread_create(thread_process3, NULL, "my_thread3");
if(IS_ERR(my_thread3))
{
err = PTR_ERR(my_thread3);
my_thread3 = NULL;
printk(KERN_ERR "unable to start kernel thread3:%d\n", err);
return err;
}
my_thread4 = kthread_create(thread_process4, NULL, "my_thread4");
if(IS_ERR(my_thread4))
{
err = PTR_ERR(my_thread4);
my_thread4 = NULL;
printk(KERN_ERR "unable to start kernel thread4:%d\n", err);
return err;
}
wake_up_process(my_thread1);
wake_up_process(my_thread2);
wake_up_process(my_thread3);
wake_up_process(my_thread4);
printk("%s:all kernel thread start;\n", __FUNCTION__);
return 0;
}
static void __exit study_exit(void)
{
int ret = -1;
printk("%s\n",__PRETTY_FUNCTION__);
if(my_thread1)
{
ret = kthread_stop(my_thread1);
my_thread1 = NULL;
printk("kernel thread1 stop,exit code is %d;\n",ret);
}
if(my_thread2)
{
ret = kthread_stop(my_thread2);
my_thread2 = NULL;
printk("kernel thread2 stop,exit code is %d;\n",ret);
}
if(my_thread3)
{
ret = kthread_stop(my_thread3);
my_thread3 = NULL;
printk("kernel thread3 stop,exit code is %d;\n",ret);
}
if(my_thread4)
{
ret = kthread_stop(my_thread4);
my_thread4 = NULL;
printk("kernel thread4 stop,exit code is %d;\n",ret);
}
printk("%s:all kernel thread stop;\n", __FUNCTION__);
}
module_init(study_init);
module_exit(study_exit);