pthread_rwlock读写锁的使用细节

在使用的过程中,往往会有一些细节上的疑问,心中会有模棱两可的地方,然后自己做了试验,并记录下来。

首先,我们先来看一下 pthread_rwlock_t 结构体的定义:

  struct
  {
    int __lock;
    unsigned int __nr_readers;   
    unsigned int __readers_wakeup;
    unsigned int __writer_wakeup;
    unsigned int __nr_readers_queued;
    unsigned int __nr_writers_queued;
    /* FLAGS must stay at this position in the structure to maintain
       binary compatibility.  */
    unsigned char __flags;
    unsigned char __shared;
    unsigned char __pad1;
    unsigned char __pad2;
    int __writer;
  } __data;
# endif
  char __size[__SIZEOF_PTHREAD_RWLOCK_T];
  long int __align;
} pthread_rwlock_t;

在多线程编程中,死锁问题是比较难定位的一种,通过调用栈我们查看此时的pthread_rwlock_t信息,对我们定位问题的帮助是很大的。

我们通常关注的字段有:

1. __nr_readers,

2. __nr_readers_queued,

3. __nr_writers_queued,

4. __writer

那这四个字段,那当我们线程加锁时,是怎么反应并记录到这个结构体中的呢?

1. 当我们使用pthread_rwlock_rdlock()获取一次读锁时,__nr_readers字段就会加一,注意,就算是同一个线程,在已经获得读锁的情况下,再去获取读锁,__nr_readers字段仍然会加一的,当我们调用pthread_rwlock_unlock()一次时,__nr_readers就会减一,如果我们重复加了读锁,必须重复调用pthread_rwlock_unlock()来使__nr_readers减一,否则其他线程再想获取写锁时,是会阻塞的。

2.__writer记录此时是谁占用着写锁,每一个线程都会有用同的ID号表示。

3.__nr_readers_queued和__nr_writers_queued字段表示有多少线程正等待加锁。这里有一点值得注意的地方就是,当想要获取读锁,但是发现__nr_writers_queued字段不为0,可就是有别的线程在等待获取写锁时,且该线程的优先级高于或想同于自己的优先级时,自己是无法或许读锁的,即使当前pthread_rwlock_t只是被加了读锁,但是有高优先级的线程已经在等待加写锁,自己仍然阻塞,为什么要这样呢?如果不这样,那读锁就会很有可能被一直占着,想加写锁的被饿死的情况。

4. 如果自己已经获取了一次读锁,但是却错误的调用了两次pthread_rwlock_unlock(),会出现什么情况呢?自己在ubuntu上试了一下,__nr_readers变成了一个很大的数,也就是0又减一了,造成以后的写锁可能再也获取不了了!

5. 如果自己已经获取了写锁,再去加读锁,pthread_rwlock_wrlock()是会返回出错的。

6. 如果自己已经获取了读锁,再去加写锁,会出现死锁的。


  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在基于 rt-thread 的系统中,可以使用 `struct rt_semaphore` 结构体来实现读写锁的控制。具体实现可以参考以下代码: ``` struct rt_semaphore rw_sem; int read_count; /* 初始化读写锁 */ int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr) { /* 初始化信号量,初始值为 1 */ rt_sem_init(&rw_sem, "rw_sem", 1, RT_IPC_FLAG_FIFO); read_count = 0; return 0; } /* 销毁读写锁 */ int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) { /* 删除信号量 */ rt_sem_delete(&rw_sem); return 0; } /* 对读写锁进行读锁定 */ int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) { /* 获取信号量,如果信号量值为 0,则线程阻塞 */ rt_sem_take(&rw_sem, RT_WAITING_FOREVER); read_count++; return 0; } /* 对读写锁进行写锁定 */ int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) { /* 获取信号量,如果信号量值为 0,则线程阻塞 */ rt_sem_take(&rw_sem, RT_WAITING_FOREVER); while (read_count > 0) { /* 如果有读线程在使用,则等待读线程全部释放 */ rt_sem_release(&rw_sem); rt_sem_take(&rw_sem, RT_WAITING_FOREVER); } return 0; } /* 对读写锁进行解锁 */ int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) { /* 释放信号量 */ rt_sem_release(&rw_sem); read_count--; return 0; } ``` 在上述代码中,我们使用了一个信号量来实现读写锁的控制。信号量的初始值为 1,表示读写锁是未锁定状态。当线程需要对读写锁进行锁定时,首先需要获取信号量,如果信号量的值为 0,则线程阻塞等待。对于读锁,只需要将读计数器 `read_count` 加 1 即可;对于写锁,则需要判断是否有读线程在使用,如果有,则等待读线程全部释放后再获取锁。对于解锁操作,只需要释放信号量并将读计数器减 1 即可。 上述代码中的函数名和参数与 POSIX 标准中定义的函数名和参数保持一致,因此可以直接调用这些函数来实现读写锁的控制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值