多线程对同一个变量进行操作时,总是有读有写。一般情况下,读的频率大于写的频率。多线程同时对一个变量进行读操作是被允许的,而同时对一个变量进行写操作或某些线程对变量进行读操作,另一些线程对变量进行写操作是不被允许的。如果使用互斥量,那同时只能有一个线程对变量进行操作,则影响的程序执行的效率。为此,pthread
库提供了读写锁。
#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8
typedef union
{
char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T];
long int __align;
} pthread_rwlockattr_t;
int pthread_rwlockattr_init(pthread_rwlockattr_t *attr);
int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr);
int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *restrict attr,
int *restrict pshared);
int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int pshared);
获取或设置读写锁属性对象中的进程共享
属性。进程共享
属性可以设置为以下值:
PTHREAD_PROCESS_SHARED
设置为该值,允许任何有权限访问的线程访问分配读写锁的内存,即使读写锁是在由多个进程共享的内存中分配的
PTHREAD_PROCESS_PRIVATE
读写锁只能由与初始化读写锁的线程在统一进程内创建的线程操作。如果不同进程的线程尝试操作该读写锁,则行为是未定义。该值为默认值。
注意
设置或获取一个未初始化的读写锁属性对象,将导致不确定性行为。
int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t *attr, int pref);
int pthread_rwlockattr_getkind_np(const pthread_rwlockattr_t *attr, int *pref);
获取或设置读写锁属性对象中的锁类型
属性。锁类型
属性有以下可选值:
PTHREAD_RWLOCK_PREFER_READER_NP
该属性是默认值。一个线程可以拥有多个读锁。根据The Single Unix Specification
,当读取器尝试放置锁,但无写入锁的写入器正在等待时,此时的行为是未定义的。当锁类型被设置为PTHREAD_RWLOCK_PREFER_READER_NP
时,则读写器优先。这意味着机器写入器正在等待,读取器将收到请求的锁。只要读取器一直存在,写入器将处于饥饿状态。
PTHREAD_RWLOCK_PREFER_WRITER_NP
This is intended as the write lock analog of PTHREAD_RWLOCK_PREFER_READER_NP
. This is ignored by glibc
because the POSIX
requirement to support recursive writer locks would cause this option to create trivial deadlocks; instead use PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
which ensures the application developer will not take recursive read locks thus avoiding deadlocks.
PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
Setting the lock kind to this avoids writer starvation as long as any read locking is not done in a recursive fashion.
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,
const pthread_rwlockattr_t *restrict attr);
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
源码
#include
#include
#include
#include
int g_num = 0;
pthread_rwlock_t rwlock;
void *start_routine_01(void *ptr)
{
for (size_t i = 0; i < 5; i++)
{
pthread_rwlock_rdlock(&rwlock);
for (size_t i = 0; i < 2; i++)
{
printf("读线程(%lu)获取全局变量当前值(%d)\n", pthread_self(), g_num);
sleep(1);
}
pthread_rwlock_unlock(&rwlock);
sleep(1);
}
return (void *)NULL;
}
void *start_routine_02(void *ptr)
{
for (size_t i = 0; i < 5; i++)
{
pthread_rwlock_rdlock(&rwlock);
for (size_t i = 0; i < 2; i++)
{
printf("读线程(%lu)获取全局变量当前值(%d)\n", pthread_self(), g_num);
sleep(1);
}
pthread_rwlock_unlock(&rwlock);
sleep(1);
}
return (void *)NULL;
}
void *start_routine_03(void *ptr)
{
for (size_t i = 0; i < 5; i++)
{
pthread_rwlock_wrlock(&rwlock);
printf("写线程(%lu)设置全局变量当前值(%d)\n", pthread_self(), ++g_num);
pthread_rwlock_unlock(&rwlock);
sleep(2);
}
return (void *)NULL;
}
int main(int argc, char const *argv[])
{
pthread_rwlockattr_t attr;
pthread_rwlockattr_init(&attr);
pthread_rwlock_init(&rwlock, &attr);
pthread_rwlockattr_destroy(&attr);
pthread_t thread_id_01, thread_id_02, thread_id_03;
pthread_create(&thread_id_01, NULL, start_routine_01, NULL);
pthread_create(&thread_id_02, NULL, start_routine_02, NULL);
pthread_create(&thread_id_03, NULL, start_routine_03, NULL);
pthread_join(thread_id_01, NULL);
pthread_join(thread_id_02, NULL);
pthread_join(thread_id_03, NULL);
pthread_rwlock_destroy(&rwlock);
exit(EXIT_SUCCESS);
}
输出
读线程(140456693409536)获取全局变量当前值(0)
读线程(140456685016832)获取全局变量当前值(0)
读线程(140456693409536)获取全局变量当前值(0)
读线程(140456685016832)获取全局变量当前值(0)
写线程(140456676624128)设置全局变量当前值(1)
读线程(140456685016832)获取全局变量当前值(1)
读线程(140456693409536)获取全局变量当前值(1)
读线程(140456685016832)获取全局变量当前值(1)
读线程(140456693409536)获取全局变量当前值(1)
写线程(140456676624128)设置全局变量当前值(2)
读线程(140456685016832)获取全局变量当前值(2)
读线程(140456693409536)获取全局变量当前值(2)
读线程(140456685016832)获取全局变量当前值(2)
读线程(140456693409536)获取全局变量当前值(2)
写线程(140456676624128)设置全局变量当前值(3)
读线程(140456685016832)获取全局变量当前值(3)
读线程(140456693409536)获取全局变量当前值(3)
读线程(140456685016832)获取全局变量当前值(3)
读线程(140456693409536)获取全局变量当前值(3)
写线程(140456676624128)设置全局变量当前值(4)
读线程(140456685016832)获取全局变量当前值(4)
读线程(140456693409536)获取全局变量当前值(4)
读线程(140456685016832)获取全局变量当前值(4)
读线程(140456693409536)获取全局变量当前值(4)
写线程(140456676624128)设置全局变量当前值(5)