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");
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一叶知秋yyds

分享是一种美德,感谢金主打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值