线程同步之读写锁属性
本文介绍了线程的同步对象读写锁的属性,通过读写锁属性可以控制在线程之间使用读写锁同步时的行为。
线程的读写锁仅支持进程共享属性。
属性介绍
数据类型:pthread_rwlockattr_t
。
初始化相关函数:
#include <pthread.h>
int pthread_rwlockattr_destroy(pthread_rwlockattr_t* attr);
int pthread_rwlockattr_init(pthread_rwlockattr_t* attr);
// 返回值:成功返回0,失败返回错误编号
pthread_rwlockattr_init()
函数使用默认值初始化读写锁属性attr
。
进程共享属性
与互斥量的进程共享属性类似,用于进程间同步访问共享变量。
下面两个函数用于获取以及设置读写锁的进程共享属性:
#include <pthread.h>
int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t* restrict attr, int* restrict pshared);
int pthread_rwlockattr_setpshared(pthread_rwlockattr_t* attr, int pshared);
// 返回值:成功返回0,失败返回错误编号
可取值为PTHREAD_PROCESS_PRIVATE
与PTHREAD_PROCESS_SHARED
,默认值为PTHREAD_PROCESS_PRIVATE
。
示例
下面的示例中,演示了读写锁是如何进行多进程间同步的。
父子进程在共享内存中的读写锁的保护下对计数器进行加法操作。
但是这个例子中并没有给出,父子进程中其中一个突然意外终止,其他进程如何来恢复的处理。因为有一个进程突然终止,其他进程就会一直阻塞。
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define SHARED_MEMORY_KEY 1234
#define SHARED_MEMORY_SIZE 1024
typedef struct
{
pthread_rwlock_t rwlock; // 互斥量保证父子进程之间的同步
int counter; // 父子进程之间对该变量进行同步+1
} SharedData; // 共享内存数据
void* childProcess(void* arg)
{
SharedData* sharedData = (SharedData*)arg;
// 加锁
pthread_rwlock_wrlock(&(sharedData->rwlock));
printf("Child process: Counter before increment: %d\n", sharedData->counter);
// 增加计数器
sharedData->counter++;
printf("Child process: Counter after increment: %d\n", sharedData->counter);
// 解锁
pthread_rwlock_unlock(&(sharedData->rwlock));
return NULL;
}
int main()
{
int sharedMemoryId;
SharedData* sharedData;
// 创建共享内存
sharedMemoryId = shmget(SHARED_MEMORY_KEY, sizeof(SharedData), IPC_CREAT | 0666);
if (sharedMemoryId < 0)
{
perror("shmget");
exit(1);
}
// 连接到共享内存
sharedData = shmat(sharedMemoryId, NULL, 0);
if (sharedData == (void*)-1)
{
perror("shmat");
exit(1);
}
// 初始化互斥量
pthread_rwlockattr_t rwlockAttr;
pthread_rwlockattr_init(&rwlockAttr);
// 设置读写锁的进程共享属性,使其能够在父子进程之间同步
pthread_rwlockattr_setpshared(&rwlockAttr, PTHREAD_PROCESS_SHARED);
pthread_rwlock_init(&(sharedData->rwlock), &rwlockAttr);
// 初始化计数器
sharedData->counter = 0;
// 创建子进程
pid_t pid = fork();
if (pid < 0)
{
perror("fork");
exit(1);
}
if (pid == 0)
{
// 子进程
int i = 0;
while (i < 5)
{
childProcess(sharedData);
i++;
sleep(1);
}
// 分离共享内存
shmdt(sharedData);
}
else
{
int i = 0;
while (i < 5)
{
// 加锁
pthread_rwlock_wrlock(&(sharedData->rwlock));
printf("Parent process: Counter before increment: %d\n", sharedData->counter);
sharedData->counter++;
printf("Parent process: Counter after increment: %d\n", sharedData->counter);
// 解锁
pthread_rwlock_unlock(&(sharedData->rwlock));
i++;
sleep(1);
}
// 等待子进程结束
wait(NULL);
// 分离共享内存
shmdt(sharedData);
// 删除共享内存
shmctl(sharedMemoryId, IPC_RMID, NULL);
}
return 0;
}
// Parent process: Counter before increment: 0
// Parent process: Counter after increment: 1
// Child process: Counter before increment: 1
// Child process: Counter after increment: 2
// Child process: Counter before increment: 2
// Child process: Counter after increment: 3
// Parent process: Counter before increment: 3
// Parent process: Counter after increment: 4
// Child process: Counter before increment: 4
// Child process: Counter after increment: 5
// Parent process: Counter before increment: 5
// Parent process: Counter after increment: 6
// Parent process: Counter before increment: 6
// Parent process: Counter after increment: 7
// Child process: Counter before increment: 7
// Child process: Counter after increment: 8
// Parent process: Counter before increment: 8
// Parent process: Counter after increment: 9
// Child process: Counter before increment: 9
// Child process: Counter after increment: 10
存在问题
由于读写锁没有健壮属性,因此如果有其他进程在持有读写锁时终止,会导致其他进程阻塞在该读写锁上,恢复读写锁的工作需要使用者自己来处理。
因此正常情况下不推荐使用读写锁来进行进程间的同步工作。
- 原文作者:生如夏花
- 原文链接:https://blduan.top/post/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/apue/%E7%BA%BF%E7%A8%8B%E5%90%8C%E6%AD%A5%E4%B9%8B%E8%AF%BB%E5%86%99%E9%94%81%E5%B1%9E%E6%80%A7/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。