Linux读写锁的使用

目录

1. 读写锁介绍

2. 读写锁的操作函数

3. 读写锁示例代码


1. 读写锁介绍

读写锁的类型可以分为读锁和写锁,以读方式给数据加锁—读锁。以写方式给数据加锁—写锁。但是读写锁是一把锁,每个线程只可以带一个锁类型。

特性:(举例说明)

1. 线程A加读锁成功,又来了三个线程,做读操作,三个线程再次加锁成功。

———结论:读时共享,并行处理

2.线程A加写锁成功,又来了三个线程,做读操作,三个线程再次加锁失败。

———结论:写时独占

3.线程A加锁成功,又来了线程B加写锁阻塞,又来了C线程加读锁阻塞。

———结论:(1)读写不能同时进行,(2)写的优先级高

举例:线程A持写锁,B请求读锁,C请求写锁。

          B,C线程先阻塞;A解锁后,C加写锁成功,B继续阻塞;C解锁后,B加锁成功。

2. 读写锁的操作函数

读写锁的过程和互斥锁类似,不作详细介绍,由特性可知,相较于互斥锁而言,当读线程多的时候,可以提高访问效率。适合使用在读操作的次数远大于写操作的时候,读写锁的相关函数如下:

主要操作函数:
1. 创建读写锁
pthread_rwlock_t  rwlock;

2. 初始化读写锁
int pthread_rwlock_init(
    pthread_rwlock_t *restrict rwlock,
    const pthread_rwlockattr_t *restrict attr
    );

3. 加读锁
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
阻塞:之前对这边锁加写锁操作时阻塞	

4. 尝试加读锁,try
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

5. 加写锁
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);	
阻塞:上一次加读锁和写锁任意一种,没有解锁都会阻塞。

6. 尝试加写锁
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);	

7. 解锁
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

8.销毁
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

以上函数都是成功返回0,失败返回错误号。

3. 读写锁示例代码

/* 3个线程不定时 "全局资源,5个线程不定时 "同一全局资源 */ 

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <pthread.h>
 
// 全局变量
int number;
pthread_rwlock_t rwlock;
 
void* write_func(void* arg)
{
    while(1)
    {
		//加写锁
        pthread_rwlock_wrlock(&rwlock);
        number++;
        printf("+++ write number: %d\n", number);
		//解锁
        pthread_rwlock_unlock(&rwlock);
		usleep(1000);
    }
    return NULL;
}
 
void* read_func(void* arg)
{
    while(1)
    {
		
        pthread_rwlock_rdlock(&rwlock);
        printf("--- read number: %d\n", number);
        pthread_rwlock_unlock(&rwlock);
        usleep(500);
    }
    return NULL;
}
 
int main(int argc, const char* argv[])
{
    pthread_t thid[8];
 
    pthread_rwlock_init(&rwlock, NULL);
 
    // 创建3个写线程
    for(int i=0; i<3; ++i)
    {
        pthread_create(&thid[i], NULL, write_func, NULL);
    }
	//创建5个读线程
    for(int i=3; i<8; ++i)
    {
        pthread_create(&thid[i], NULL, read_func, NULL);
    }
 
    // 回收子线程的pcb
    for(int i=0; i<8; ++i)
    {
        pthread_join(thid[i], NULL);
    }
	
	//释放读写锁资源
    pthread_rwlock_destroy(&rwlock);
 
    return 0;
}

运行结果:一直循环下去。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
读写锁是用于多线程环境下保护共享资源的一种机制。在 Linux 内核中,读写锁的实现是基于 spinlock 和原子操作的。下面我将简单介绍一下 Linux 内核中读写锁的源码实现。 读写锁的定义: ```c typedef struct { raw_rwlock_t raw_lock; } rwlock_t; ``` 其中,raw_rwlock_t 是一个原始读写锁类型,它是由内核提供的一个结构体类型,定义在 include/linux/spinlock_types.h 文件中。 raw_rwlock_t 的定义: ```c typedef struct { arch_rwlock_t raw_lock; } raw_rwlock_t; typedef struct { unsigned int lock; } arch_rwlock_t; ``` 其中,arch_rwlock_t 是一个体系结构相关的原始读写锁类型,它的实现由不同的处理器架构提供。 下面是 x86_64 架构下的 arch_rwlock_t 实现: ```c struct __arch_rwlock { unsigned int lock; }; typedef struct __arch_rwlock arch_rwlock_t; ``` 可以看到,在 x86_64 架构下,arch_rwlock_t 只包含一个 unsigned int 类型的 lock 成员变量,用于存储锁状态。 读写锁的初始化: ```c void rwlock_init(rwlock_t *lock) { raw_spin_lock_init(&lock->raw_lock.spinlock); atomic_long_set(&lock->raw_lock.rw_sem, 0); } ``` 其中,raw_spin_lock_init() 用于初始化写锁,atomic_long_set() 用于初始化读计数器。 读锁的获取: ```c void read_lock(rwlock_t *lock) { while (1) { long count = atomic_long_read(&lock->raw_lock.rw_sem); if (count >= 0) { if (atomic_long_cmpxchg(&lock->raw_lock.rw_sem, count, count + 1) == count) { break; } } else { cpu_relax(); } } raw_spin_lock(&lock->raw_lock.spinlock); } ``` 其中,atomic_long_read() 用于读取读计数器的值,如果值大于等于 0,则表示读锁可用,此时使用 atomic_long_cmpxchg() 原子操作来增加读计数器并获取读锁;如果值小于 0,则表示有写锁在使用,此时使用 cpu_relax() 函数等待写锁释放。 读锁的释放: ```c void read_unlock(rwlock_t *lock) { raw_spin_unlock(&lock->raw_lock.spinlock); atomic_long_dec(&lock->raw_lock.rw_sem); } ``` 其中,raw_spin_unlock() 用于释放写锁,atomic_long_dec() 用于减少读计数器的值。 写锁的获取: ```c void write_lock(rwlock_t *lock) { raw_spin_lock(&lock->raw_lock.spinlock); while (1) { long count = atomic_long_read(&lock->raw_lock.rw_sem); if (count == 0) { if (atomic_long_cmpxchg(&lock->raw_lock.rw_sem, 0, -1) == 0) { break; } } else { cpu_relax(); } } } ``` 其中,raw_spin_lock() 用于获取写锁,atomic_long_read() 用于读取读计数器的值,如果值等于 0,则表示读锁未被使用,此时使用 atomic_long_cmpxchg() 原子操作将读计数器的值修改为 -1 并获取写锁;如果值大于 0,则表示有读锁在使用,此时使用 cpu_relax() 函数等待读锁释放。 写锁的释放: ```c void write_unlock(rwlock_t *lock) { atomic_long_set(&lock->raw_lock.rw_sem, 0); raw_spin_unlock(&lock->raw_lock.spinlock); } ``` 其中,atomic_long_set() 用于将读计数器的值设为 0,raw_spin_unlock() 用于释放写锁。 以上就是 Linux 内核中读写锁的源码实现。值得注意的是,在多处理器环境下,读写锁的实现可能会涉及到更复杂的机制,例如写者优先等待、读者优先等待等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值