linux 内核同步互斥技术之读写信号量
读写信号量
读写信号量是对互斥信号量的改进,允许多个读者同时进入临界区,读者和写者互斥,写者和写者互斥,适合在以读为主的情况使用。
读写信号量的定义如下:
include/linux/rwsem.h
struct rw_semaphore {
? ? atomic_long_t 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
};
初始化静态读写信号量的方法如下:
DECLARE_RWSEM(name);
在运行时动态初始化读写信号量的方法如下:
init_rwsem(sem);
申请读锁的函数如下
(1) void down_read(struct rw_semaphore *sem);
申请读锁,如果写者占有写锁或者正在等待写锁,那么进程深度睡眠。
(2) int down_read_trylock(struct rw_semaphore *sem);
尝试申请读锁,不会等待。如果申请成功,返回 1;否则返回 0。
释放读锁的函数如下:
void up_read(struct rw_semaphore *sem);
申请写锁的函数如下
(1) void down_write(struct rw_semaphore *sem);
申请写锁,如果写者占有写锁或者读者占有读锁,那么进程深度睡眠。
(2) int down_write_killable(struct rw_semaphore *sem);
申请写锁,如果写者占有写锁或者读者占有读锁,那么进程中度睡眠。
(3) int down_write_trylock(struct rw_semaphore *sem);
尝试申请写锁,不会等待。如果申请成功,返回 1;否则返回 0。
占有写锁以后,可以把写锁降级为读锁,函数如下
void downgrade_write(struct rw_semaphore *sem);
释放写锁的函数如下:
void up_write(struct rw_semaphore *sem);
rw_semaphore 我之前一直没有从代码理解如何实现的。只知道理论上是可以多个读者去读,如果有写者就不能去读。最近看这块代码,代码实现上是:在等待队列中如果有写者,把写者之前的读者唤醒,写者还是在等待队列中。如果等待队列中写者之前没有读者那就只唤醒写者,写者后面的还继续在等待队列中等待。
实例
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kthread.h>?
#include <linux/rwsem.h>
#include <linux/delay.h>
static DECLARE_RWSEM(my_rw_semaphore);
struct task_struct * task1;
struct task_struct * task2;
struct task_struct * task3;
struct task_struct * task4;
struct task_struct * task5;
int thread_print_first(void *p) {
? ? if(kthread_should_stop()){
? ? ? ? return 0;
? ? }
? ? printk(KERN_ALERT"Hello World:first writer\n");
? ? down_write(&my_rw_semaphore);
? ? printk(KERN_ALERT"Hello World:first writting\n");
? ? msleep(5000);
? ? up_write(&my_rw_semaphore);
? ? printk(KERN_ALERT"Hello World:first written\n");
? ? do {
? ? ? ? msleep(1000);
? ? }
? ? while(!kthread_should_stop());
? ? return 0;
}
int thread_print_second(void *p) {
? ? if(kthread_should_stop()){
? ? ? ? return 0;
? ? }
? ? printk(KERN_ALERT"Hello World:second reader\n");
? ? down_read(&my_rw_semaphore);
? ? printk(KERN_ALERT"Hello World:second reading\n");
? ? msleep(5000);
? ? up_read(&my_rw_semaphore);
? ? printk(KERN_ALERT"Hello World:second read\n");
? ? do {
? ? ? ? msleep(1000);
? ? }
? ? while(!kthread_should_stop());
? ? return 0;
}
int thread_print_third(void *p) {
? ? if(kthread_should_stop()){
? ? ? ? return 0;
? ? }
? ? printk(KERN_ALERT"Hello World:third reader\n");
? ? down_read(&my_rw_semaphore);
? ? printk(KERN_ALERT"Hello World:third reading\n");
? ? msleep(5000);
? ? up_read(&my_rw_semaphore);
? ? printk(KERN_ALERT"Hello World:third read\n");
? ? do {
? ? ? ? msleep(1000);
? ? }
? ? while(!kthread_should_stop());
? ? return 0;
}
int thread_print_fourth(void *p) {
? ? if(kthread_should_stop()){
? ? ? ? return 0;
? ? }
? ? msleep(100);
? ? printk(KERN_ALERT"Hello World:fourth writer\n");
? ? down_write(&my_rw_semaphore);
? ? printk(KERN_ALERT"Hello World:fourth writting\n");
? ? msleep(5000);
? ? up_write(&my_rw_semaphore);
? ? printk(KERN_ALERT"Hello World:fourth written\n");
? ? do {
? ? ? ? msleep(1000);
? ? }
? ? while(!kthread_should_stop());
? ? return 0;
}
int thread_print_fifth(void *p) {
? ? if(kthread_should_stop()){
? ? ? ? return 0;
? ? }
? ? msleep(200);
? ? printk(KERN_ALERT"Hello World:fifth reader\n");
? ? down_read(&my_rw_semaphore);
? ? printk(KERN_ALERT"Hello World:fifth reading\n");
? ? msleep(5000);
? ? up_read(&my_rw_semaphore);
? ? printk(KERN_ALERT"Hello World:fifth read\n");
? ? do {
? ? ? ? msleep(1000);
? ? }
? ? while(!kthread_should_stop());
? ? return 0;
}
static int hello_init(void) {
? ? printk(KERN_ALERT"Hello World enter\n");
? ? task1 = kthread_create(thread_print_first,NULL,"first");
? ? if(IS_ERR(task1)) {
? ? ? ? printk(KERN_ALERT"kthread_create error!\n");
? ? ? ? return -1;
? ? }
? ? task2 = kthread_create(thread_print_second,NULL,"second");
? ? if(IS_ERR(task2)) {
? ? ? ? printk(KERN_ALERT"kthread_create error!\n");
? ? ? ? kthread_stop(task1);
? ? ? ? return -1;
? ? }
? ? task3 = kthread_create(thread_print_third,NULL,"third");
? ? if(IS_ERR(task3)) {
? ? ? ? printk(KERN_ALERT"kthread_create error!\n");
? ? ? ? kthread_stop(task1);
? ? ? ? kthread_stop(task2);
? ? ? ? return -1;
? ? }
? ? task4 = kthread_create(thread_print_fourth,NULL,"fourth");
? ? if(IS_ERR(task4)) {
? ? ? ? printk(KERN_ALERT"kthread_create error!\n");
? ? ? ? kthread_stop(task1);
? ? ? ? kthread_stop(task2);
? ? ? ? kthread_stop(task3);
? ? ? ? return -1;
? ? }
? ? task5 = kthread_create(thread_print_fifth,NULL,"fifth");
? ? if(IS_ERR(task5)) {
? ? ? ? printk(KERN_ALERT"kthread_create error!\n");
? ? ? ? kthread_stop(task1);
? ? ? ? kthread_stop(task2);
? ? ? ? kthread_stop(task3);
? ? ? ? kthread_stop(task4);
? ? ? ? return -1;
? ? }
? ? wake_up_process(task1);
? ? wake_up_process(task2);
? ? wake_up_process(task3);
? ? wake_up_process(task4);
? ? wake_up_process(task5);
? ? return 0;
}
static void hello_exit(void) {
? ? int ret;
? ? if (!IS_ERR(task1)) {
? ? ? ? ret = kthread_stop(task1);
? ? ? ? printk("<<<<<<<<task1 exit, ret = %d\n", ret);
? ? }
? ? if (!IS_ERR(task2)) {
? ? ? ? ret = kthread_stop(task2);
? ? ? ? printk("<<<<<<<<task2 exit, ret = %d\n", ret);
? ? }
? ? if (!IS_ERR(task3)) {
? ? ? ? ret = kthread_stop(task3);
? ? ? ? printk("<<<<<<<<task3 exit, ret = %d\n", ret);
? ? }
? ? if (!IS_ERR(task4)) {
? ? ? ? ret = kthread_stop(task4);
? ? ? ? printk("<<<<<<<<task4 exit, ret = %d\n", ret);
? ? }
? ? if (!IS_ERR(task5)) {
? ? ? ? ret = kthread_stop(task5);
? ? ? ? printk("<<<<<<<<task5 exit, ret = %d\n", ret);
? ? }
? ? printk(KERN_ALERT"hello world exit\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
?
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!