linux读写锁pthread_rwlock_t

读写锁说明

读写锁实际是一种特殊的自旋锁,它把对共享资源的访问者划分成读者和写者,这种锁相对于自旋锁而言,能提高并发性,它允许同时有多个读者来访问共享资源。写者是排他性的,一个读写锁同时只能有一个写者或多个读者,但不能同时既有读者又有写者。

1、一次只有一个线程可以占有写模式的读写锁, 但是可以有多个线程同时占有读模式的读写锁。
2、当读写锁是写加锁状态时, 在这个锁被解锁之前, 所有试图对这个锁加锁的线程都会被阻塞。
3、当读写锁在读加锁状态时, 所有试图以读模式对它进行加锁的线程都可以得到访问权, 但是如果线程希望以写模式对此锁进行加锁, 它必须直到所有的线程释放锁。
4、读写锁适合于对数据结构的读次数比写次数多得多的情况. 因为, 读模式锁定时可以共享, 以写模式锁住时意味着独占, 所以读写锁又叫共享-独占锁。

适用场景:
1、读的次数远大于写的次数。
2、读和写执行的时间都很短(自旋锁获得锁失败时会在原地自旋,直到获得锁,等待时间太长会浪费CPU资源)。

linux读写锁:

pthread_rwlock_t是linux读写锁,初始化和使用与互斥锁pthread_mutex_t类似,加锁时分加读锁和加写锁,解锁一样。

pthread_rwlock_t g_rwlock; // 定义一把读写锁
pthread_rwlock_init(&g_rwlock, NULL); // 初始化读写锁

pthread_rwlock_rdlock(&g_rwlock); // 请求读锁
pthread_rwlock_wrlock(&g_rwlock); // 请求写锁
pthread_rwlock_unlock(&g_rwlock); // 解锁

pthread_rwlock_destroy(&g_rwlock);// 销毁读写锁

pthread_rwlock_t示例

1、pthread_rwlock_t读写锁默认是读优先的。
2、如果是单线程读,单线程写,优先级意义不大,两个线程会轮流获得锁。
(下面是两个线程读,两个线程写)
3、如果默认使用读优先,两个读线程会轮流获得锁,在此期间写线程很难获得锁,出现写锁饥饿状态。
4、设置写优先,写线程优先执行,读写锁适用的场景是读的多写的少,因此建议设置写优先。

读优先:防止出现写锁饥饿,写操作较难执行。
写优先:防止递归调用BUG,下面伪代码thread1第一次readlock后,这时thread2写锁来了,thread1 第二次readlock只能等待,但前一个readlock又没有释放,就造成死锁。

thread1 readlock  readlock unlock unlock
thread2 writelock

代码示例

#include <unistd.h>
pthread_rwlock_t g_rwlock; // 定义一把读写锁
pthread_t m_tid[4];//线程组
int number = 0;//一个全局变量
void* readThread0(void*)
{
    
    
    for(int index=0;index<5;index++)
    {
    
    
        pthread_rwlock_rdlock(&g_rwlock); // 请求读锁
        printf("readThread0,number=%d\n",number);
        usleep(1*100);// 模拟做业务
        pthread_rwlock_unlock(&g_rwlock); // 开锁
    }
    return NULL;
}

void* readThread1(void*)
{
    
    
    for(int index=0;index<5;index++)
    {
    
    
        pthread_rwlock_rdlock(&g_rwlock); // 请求读锁
        printf("readThread1,number=%d\n",number);
        usleep(1*100);// 模拟做业务
        pthread_rwlock_unlock(&g_rwlock); // 开锁
    }
    return NULL;
}

void* writeThread2(void*)
{
    
    
    for(int index=0;index<5;index++)
    {
    
    
        pthread_rwlock_wrlock(&g_rwlock); // 请求写锁
        number ++;
        printf("writeThread2,number=%d\n",number);
        usleep(1*100);// 模拟做业务
        pthread_rwlock_unlock(&g_rwlock); // 开锁
    }
    return NULL;
}

void* writeThread3(void*)
{
    
    
    for(int index=0;index<5;index++)
    {
    
    
        pthread_rwlock_wrlock(&g_rwlock); // 请求写锁
        number ++;
        printf("writeThread3,number=%d\n",number);
        usleep(1*100);// 模拟做业务
        pthread_rwlock_unlock(&g_rwlock); // 开锁
    }
    return NULL;
}

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{
    
    
    ui->setupUi(this);

    setbuf(stdout,nullptr);
    pthread_rwlock_init(&g_rwlock, NULL); // 初始化读写锁

    //设置写优先
    pthread_rwlockattr_t attr;
    pthread_rwlockattr_init(&attr);
    pthread_rwlockattr_setkind_np (&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
    (void)pthread_rwlock_init(&g_rwlock, &attr);

    pthread_create(&m_tid[0], NULL, readThread0, NULL);
    pthread_create(&m_tid[1], NULL, readThread1, NULL);
    pthread_create(&m_tid[3], NULL, writeThread3, NULL);
    pthread_create(&m_tid[2], NULL, writeThread2, NULL);
}

MainWindow::~MainWindow()
{
    
    
    pthread_rwlock_destroy(&g_rwlock);// 销毁读写锁
    delete ui;
}

默认读优先级,打印:

readThread0,number=0
readThread0,number=0
readThread0,number=0
readThread0,number=0
readThread0,number=0
readThread1,number=0
writeThread2,number=1
readThread1,number=1
writeThread2,number=2
readThread1,number=2
writeThread2,number=3
readThread1,number=3
writeThread2,number=4
readThread1,number=4
writeThread2,number=5
writeThread3,number=6
writeThread3,number=7
writeThread3,number=8
writeThread3,number=9
writeThread3,number=10

设置写优先,打印:

readThread1,number=0
writeThread2,number=1
writeThread2,number=2
writeThread2,number=3
writeThread2,number=4
writeThread2,number=5
writeThread3,number=6
readThread0,number=6
readThread1,number=6
writeThread3,number=7
readThread0,number=7
readThread1,number=7
writeThread3,number=8
readThread0,number=8
readThread1,number=8
writeThread3,number=9
readThread0,number=9
readThread1,number=9
writeThread3,number=10
readThread0,number=10

猜你喜欢

转载自blog.csdn.net/weixin_40355471/article/details/129784201