Linux中读写锁详细介绍
- 电脑硬件
- 2025-09-19 07:42:02

读写锁介绍
Linux 中的读写锁(Read-Write Lock)是一种用于线程同步的机制,它允许多个线程同时读取共享资源,但只允许一个线程写入共享资源。这种机制在读操作远多于写操作的场景下,可以显著提高并发性能。读写锁主要有以下特点:
读写锁区分了对共享资源的读取和写入操作。这使得它可以根据不同的操作类型,采用不同的锁定策略。
对于读锁(共享)来说,允许多个线程同时持有,用于保护读取操作,当有线程持有读锁时,其他线程也可以获取读锁。
对于写锁(独占)来说,一次只能有一个线程持有,用于保护写入操作,当有线程持有写锁时,其他线程都不能获取读锁或者写锁。
想要获取读锁和写锁的要求:
一个线程想要成功获取某资源的读锁,要求其他线程不持有任何锁或者只持有读锁可以获取成功,如果其他线程持有该资源写锁的话就获取不成功。
一个线程想要成功获取某资源的写锁,要求其他线程不持有任何锁才可以获取成功,如果其他线程持有该资源写锁或者该资源读锁的话就获取不成功。
读写锁的适用情况读写锁的优点:
提高读操作并发性:在读多写少的场景下,读写锁可以显著提高读取操作的并发性,从而提高程序的整体性能。减少线程阻塞:与互斥锁相比,读写锁减少了线程因读取操作而阻塞的概率,这提高了线程的利用率和程序的响应速度。读写锁的适用情况:
读多写少的共享资源: 例如,配置文件、数据缓存、查找表等。 需要频繁读取但很少修改的数据: 例如,传感器数据、实时监控数据等。互斥锁VS读写锁
互斥锁确保了在任何时刻只有一个线程可以访问受保护的资源,无论是读取还是写入。
读写锁的适合使用在在读操作远多于写操作的场景下,它允许多个线程同时读取共享资源,提高了读操作的并发性,但只允许一个线程写入,对于资源写操作没有提高。
读写锁的使用流程 初始化读写锁: 使用pthread_rwlock_init()创建读写锁。获取锁:读取共享资源前,使用pthread_rwlock_rdlock()获取读锁。
写入共享资源前,使用pthread_rwlock_wrlock()获取写锁。
访问共享资源: 在读写锁的保护下,安全地访问共享资源。解锁读写锁: 在完成共享资源访问后,使用pthread_rwlock_unlock()解锁读写锁。销毁读写锁: 在读写锁不再使用时,使用pthread_rwlock_destroy()销毁它。 pthread_rwlock_init():初始化读写锁函数作用:初始化一个读写锁。
函数原型:int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr);
参数:
rwlock:指向要初始化的读写锁变量的指针。attr:读写锁属性,通常设置为NULL表示使用默认属性。返回值:
成功返回0,失败返回错误码。
注意:
为了让多个线程都能使用同一个读写锁,读写锁变量必须定义于线程可以共享访问的内存区域,比如全局变量静态变量或者堆上,读写锁变量的类型为pthread_rwlock_t。使用读写锁的第一步必须是初始化读写锁,不初始化可能会出现未定义情况。通常来说pthread_rwlock_init函数的第二个参数attr我们会设置为NULL,此时会创建一个默认属性的读写锁,完全已经够用。 pthread_rwlock_rdlock():获取读锁函数作用:获取读锁。
函数原型:int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
参数:
rwlock:指向要获取读锁的读写锁变量的指针。
返回值:
成功返回0,失败返回错误码。
注意:
如果当前没有线程持有写锁,调用线程将立即获得读锁。如果当前有线程持有写锁,调用线程将被阻塞,直到写锁被释放。 pthread_rwlock_tryrdlock():尝试获取读锁函数作用:尝试获取读锁,如果读写锁已被写锁定,则不阻塞,立即返回错误。
函数原型:int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
参数:
rwlock:指向要尝试获取读锁的读写锁变量的指针。
返回值:
成功锁定返回0。如果读写锁已被写锁定,返回EBUSY。其他错误返回相应的错误码。注意:
pthread_rwlock_tryrdlock()是非阻塞的,它不会使调用线程进入等待状态。这个函数在需要非阻塞的锁定操作时很有用。 pthread_rwlock_wrlock():获取写锁函数作用:获取写锁。
函数原型:int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
参数:
rwlock:指向要获取写锁的读写锁变量的指针。
返回值:
成功返回0,失败返回错误码。
注意:
如果当前没有线程持有读锁或写锁,调用线程将立即获得写锁。如果当前有线程持有读锁或写锁,调用线程将被阻塞,直到所有锁都被释放。 pthread_rwlock_trywrlock():尝试获取写锁函数作用:尝试获取写锁,如果读写锁已被读锁定或写锁定,则不阻塞,立即返回错误。
函数原型:int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
参数:
rwlock:指向要尝试获取写锁的读写锁变量的指针。
返回值:
成功锁定返回0。如果读写锁已被读锁定或写锁定,返回EBUSY。其他错误返回相应的错误码。注意:
pthread_rwlock_trywrlock()是非阻塞的,它不会使调用线程进入等待状态。这个函数在需要非阻塞的锁定操作时很有用。 pthread_rwlock_unlock():解锁读写锁函数作用:解锁读写锁
函数原型:int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr);
参数:
rwlock:指向要解锁的读写锁变量的指针。
返回值:
成功返回0,失败返回错误码。
注意:
解锁读写锁后,其他等待该读写锁的线程可以获得锁。持有读锁或写锁的线程都可以使用这个函数解锁。一个线程对于同一个读写锁,在同一时间点上,只能拥有读锁或者写锁,不能同时拥有。
所以使用pthread_rwlock_unlock()进行解锁时,不需要指定解的是读锁还是写锁。操作系统内部会维护读写锁的状态,并且根据内部状态来确定如何解锁,这样设计简化了读写锁的使用
pthread_rwlock_destroy():销毁读写锁函数作用:销毁一个读写锁。
函数原型:int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
参数:
rwlock:指向要销毁的读写锁变量的指针。
返回值:
成功返回0,失败返回错误码。
注意:
在读写锁不再使用时,应该及时销毁它以释放资源。只有未被任何线程锁定的读写锁才能被销毁。 读写锁使用示例示例:共享数据缓存
假设我们有一个共享的数据缓存,多个线程需要读取缓存中的数据,而只有少数线程需要更新缓存。
#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> #define NUM_READERS 5 #define NUM_WRITERS 2 // 共享数据缓存 int data_cache = 0; // 读写锁 pthread_rwlock_t rwlock; // 读线程函数 void *reader_thread(void *arg) { int thread_id = *(int *)arg; // 获取读锁 pthread_rwlock_rdlock(&rwlock); // 读取共享数据 printf("Reader %d: Reading data_cache = %d\n", thread_id, data_cache); sleep(1); // 模拟耗时读取操作 // 释放读锁 pthread_rwlock_unlock(&rwlock); pthread_exit(NULL); } // 写线程函数 void *writer_thread(void *arg) { int thread_id = *(int *)arg; // 获取写锁 pthread_rwlock_wrlock(&rwlock); // 更新共享数据 data_cache++; printf("Writer %d: Updated data_cache = %d\n", thread_id, data_cache); sleep(2); // 模拟耗时写入操作 // 释放写锁 pthread_rwlock_unlock(&rwlock); pthread_exit(NULL); } int main() { pthread_t readers[NUM_READERS]; pthread_t writers[NUM_WRITERS]; int reader_ids[NUM_READERS]; int writer_ids[NUM_WRITERS]; // 初始化读写锁 if (pthread_rwlock_init(&rwlock, NULL) != 0) { perror("pthread_rwlock_init"); exit(EXIT_FAILURE); } // 创建读线程 for (int i = 0; i < NUM_READERS; i++) { reader_ids[i] = i; if (pthread_create(&readers[i], NULL, reader_thread, &reader_ids[i]) != 0) { perror("pthread_create (reader)"); exit(EXIT_FAILURE); } } // 创建写线程 for (int i = 0; i < NUM_WRITERS; i++) { writer_ids[i] = i; if (pthread_create(&writers[i], NULL, writer_thread, &writer_ids[i]) != 0) { perror("pthread_create (writer)"); exit(EXIT_FAILURE); } } // 等待读线程结束 for (int i = 0; i < NUM_READERS; i++) { pthread_join(readers[i], NULL); } // 等待写线程结束 for (int i = 0; i < NUM_WRITERS; i++) { pthread_join(writers[i], NULL); } // 销毁读写锁 if (pthread_rwlock_destroy(&rwlock) != 0) { perror("pthread_rwlock_destroy"); exit(EXIT_FAILURE); } return 0; }代码解释:
包含头文件: stdio.h:用于输入输出。stdlib.h:用于标准库函数。pthread.h:用于线程相关函数。unistd.h:用于sleep()函数。 定义共享数据和读写锁: data_cache:一个整数变量,作为共享数据缓存。rwlock:一个pthread_rwlock_t类型的变量,用于读写锁。 读线程函数reader_thread(): 每个读线程执行这个函数。首先,使用pthread_rwlock_rdlock()获取读锁。然后,读取共享数据data_cache。使用sleep()模拟耗时读取操作。最后,使用pthread_rwlock_unlock()释放读锁。 写线程函数writer_thread(): 每个写线程执行这个函数。首先,使用pthread_rwlock_wrlock()获取写锁。然后,更新共享数据data_cache。使用sleep()模拟耗时写入操作。最后,使用pthread_rwlock_unlock()释放写锁。 main()函数: 初始化读写锁:使用pthread_rwlock_init()初始化读写锁。创建读线程:创建多个读线程,并传递线程ID作为参数。创建写线程:创建多个写线程,并传递线程ID作为参数。等待线程结束:使用pthread_join()等待所有线程结束。销毁读写锁:使用pthread_rwlock_destroy()销毁读写锁。程序输出显示读线程并发读取共享数据的过程,以及写线程更新共享数据的过程。由于读写锁的保护,读线程可以并发执行,而写线程的更新操作是互斥的。
Linux中读写锁详细介绍由讯客互联电脑硬件栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“Linux中读写锁详细介绍”