0
点赞
收藏
分享

微信扫一扫

进程通信之读写锁


读写锁

读写锁的分配规则
1. 没有线程持有读写锁进行写,任意数量的线程可以持有该读写锁用于读
2. 只有没有线程持有给定的读写锁用于读或者写的时候,才能分配读写锁用于写。
如果修改数据频繁,那么可以考虑用读写锁替代互斥锁。

获取与释放

  • 如果对应的读写锁已由某个写入者持有,那么阻塞pthread_rwlock_rdlock获取读出锁
  • 如果对应的读写锁已由另一个写入者持有,那就阻塞pthread_rwlock_wrlock获取写入锁。
  • pthread_rwlock_unlock用于释放读出锁或者写入锁。
    三者成功时返回0,出错时返回正的错误值
  • pthread_rwlock_tryrdlock(pthread _rwlock_t *rwptr)尝试获取读出锁,如果不能马上获得,返回EBUSY错误。
  • pthread_rwlock_trywrlock(pthread _rwlock_t *rwptr)尝试获取写入锁,如果不能马上获得,返回EBUSY错误。

初始化和摧毁

  • 动态初始化
    ​​​int pthread_rwlock_init(pthread_rwlock_t *rwptr, const pthread_rwlockattr_t *attr)​
  • 静态初始化
    ​​​PTHREAD_RWLOCK_INITIALIZER​
  • 摧毁
    ​​​int pthread_rwlock_destroy(pthread_rwlock_t *rwptr)​

属性设置

int pthread_rwlockattr_init(pthread_rwlockattr_t * attr)
int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t * attr,int *valptr)
int pthread_rwlockattr_setpshared(pthread_rwlockattr_t * attr,int

读写锁很适合读的次数远大于写的次数的情况。
例子: 一个写者,多个读者。用读写锁进行协调工作。
code:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct data{
int number;
char info[105];
};
struct data *pdata = NULL;
pthread_rwlock_t lock;
void *read(void *arg){
int id = *((int *)arg);
while(1){
int ret;
ret = pthread_rwlock_tryrdlock(&lock);
if(ret != 0) continue;
printf("reader %d is reading!\n",id);
if(pdata == NULL) printf("data is null.\n");
else printf("data: number is %d, info are %s.\n",pdata->number,pdata->info);
pthread_rwlock_unlock(&lock);
}
pthread_exit(0);
}
void *write(void *arg){
int id = *((int *)arg);
while(1){
int ret;
ret = pthread_rwlock_trywrlock(&lock);
if(ret !=0) continue;
printf("writer %d is writing!\n",id);
if(pdata == NULL){
pdata = (struct data *)malloc(sizeof(struct data));
pdata->number = 1;
strcpy(pdata->info,"I love linux.");
printf("finish, wrote it.\n");
}
else printf("the pdata is not null.\n");
pthread_rwlock_unlock(&lock);
}
pthread_exit(0);
}
int main(){
pthread_t reader[10];
pthread_t writer;
int i;
pthread_create(&writer,NULL,write,(void *)&i);
for(i=0; i<10; i++){
pthread_create(&reader[i],NULL,read,(void *)&i);
}
//pthread_create(&writer,NULL,write,NULL);
if(pdata != NULL) free(pdata);
getchar();
return 0;
}

运行:

writer 1 is writing!
finish, wrote it.
reader 2 is reading!
data: number is 1, info are I love linux..
writer 1 is writing!
the pdata is not null.
reader 2 is reading!
data: number is 1, info are I love linux..
reader 2 is reading!
data: number is 1, info are I love linux..

线程取消函数: ​​int pthread_cancel(pthread_t tid)​​​
一个线程可以被同一进程中的其他线程取消。
与之对应的自愿终止: ​​​void pthread_exit(void *retval)​

#include <stdio.h>
#include <unistd.h>
#include "unix98.h"
#include <pthread.h>

pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
pthread_t tid1, tid2;
void *thread1(void *), *thread2(void *);
int main(){
pthread_setconcurrency(2);
pthread_create(&tid1,NULL,thread1,NULL);
sleep(1); /* let tid2 get lock. */
pthread_create(&tid2,NULL,thread2,NULL);
void *status; /* store returned value from waited tid */
pthread_join(tid2,&status);
if(status != PTHREAD_CANCELED){
printf("thread2 status = %p, status);
}
pthread_join(tid1, &status);
if(status != NULL){
printf("thread1 status = %p\n",status);
}
//printf("rw_refcount = %d, rw_nwaitreaders = %d, rw_nwaitwriter = %d\n",
// rwlock.rw_refcount,rwlock.rw_nwaitreaders, rwlock.rw_nwaitwriters);
pthread_rwlock_destroy(&rwlock);
return 0;
}
void *thread1(void *arg){
pthread_rwlock_rdlock(&rwlock);
printf("thread1 got a read lock.\n");
sleep(3); /* let thread2 block in pthread_rwlock_wrlock */
pthread_cancel(tid2);
sleep(3);
pthread_rwlock_unlock(&rwlock);
return NULL;
}
void *thread2(void *arg){
printf("thread2 try to obtain a write lock.\n");
pthread_rwlock_wrlock(&rwlock);
printf("thread2() get a write lock.\n");
sleep(1);
pthread_rwlock_unlock(&rwlock);
return

./pthread_cancel 
thread1 got a read lock.
thread2 try to obtain a write lock.
thread2() get a write

fcntl函数和读写锁

文件锁:建议性锁,强制性锁
lock结构体:

Struct flock{
short l_type;
off_t l_start;
short

flock可施加建议性锁,fcntl既可以施加建议性锁,也可施加强制性锁。
fcntl也可以对某一记录进行上锁,也就是所谓的记录锁。记录锁分为读取锁(共享锁),写入锁(排斥锁,互斥锁)。
fcntl建立记录锁:
下面是一个学习的例子,参考 ​​​http://www.jb51.net/article/37671.htm​​​
使用fcntl增加和释放锁:

#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <stdlib.h>

void lock_set(int fd,int type){
struct flock lock;
lock.l_whence = SEEK_SET; /* 相对位移量的起点是文件的开头 */
lock.l_start = 0; /* 相对位移量 */
lock.l_len = 0; /* 加锁区域的长度 */
while(1){
lock.l_type=type;
if(fcntl(fd,F_SETLK,&lock) == 0){
if(lock.l_type == F_RDLCK) printf("read lock by %d\n", getpid());
else if(lock.l_type == F_WRLCK) printf("write lock by %d\n", getpid());
else if(lock.l_type == F_UNLCK) printf("release lock by %d\n", getpid());
return ;
}
fcntl(fd,F_GETLK,&lock);
if(lock.l_type != F_UNLCK){
if(lock.l_type == F_RDLCK) printf("read lock already set by %d\n",lock.l_pid);
else if(lock.l_type == F_WRLCK) printf("write lock already set by %d\n",lock.l_pid);
printf("please enter any key to continue: ");
getchar();
}
}

}
int main(){
int fd = open("path",O_RDWR | O_CREAT, 0755); /* 当前路径下创建path */
if(fd == -1){
perror("open: ");
exit(1);
}
lock_set(fd,F_WRLCK);
puts("wait for a secend...\n");
sleep(6);
lock_set(fd,F_UNLCK);
puts("wait for a secend...\n");
sleep(1);
close(fd);
exit(0);
}

不修改上面的代码,试试写入锁 + 写入锁, 看看效果。
在不同的标签内运行此程序:

write + write

./write
write lock by 2904
wait for a secend...

release lock by 2904
wait for a secend...

./write
write lock already set by 2904
please enter any key to continue:
write lock already set by 2904
please enter any key to continue:
write lock by 2905
wait for a secend...

release lock by 2905
wait for

在已有write锁的情况下不能加上write锁。
现在,稍作修改

lock_set(fd,F_WRLCK);
--->
lock_set(fd,F_RDLCK);

write + read

./write 
write lock by 3005
wait for a secend...

release lock by 3005
wait for a secend...

./read
write lock already set by 3005
please enter any key to continue:
write lock already set by 3005
please enter any key to continue:
write lock already set by 3005
please enter any key to continue:
read lock by 3006
wait for a secend...

release lock by 3006
wait for

在已有write锁的情况下不能加上read锁

read + write

./read 
read lock by 3019
wait for a secend...

release lock by 3019
wait for a secend...

./write
read lock already set by 3019
please enter any key to continue:
read lock already set by 3019
please enter any key to continue:
read lock already set by 3019
please enter any key to continue:
read lock already set by 3019
please enter any key to continue:
write lock by 3020
wait for a secend...

release lock by 3020
wait for

在已有read锁的情况下不能加上write锁

read + read

./read
read lock by 3035
wait for a secend...

release lock by 3035
wait for a secend...

./read
read lock by 3036
wait for a secend...

release lock by 3036
wait for a

read锁和read锁不冲突。在已有read锁的情况下可以加上read锁。


举报

相关推荐

0 条评论