对于多线程程序来说,同步是指在一定的时间内只允许某一个线程访问某个资源 。 而在
此时间内,不允许其他的线程访问该资源。同步资源的方式:互斥锁、条件变量、读写锁、
信号量。
读写锁:
一、基本原理
1、读写锁的 3 种状态
1)当读写锁是写加锁状态时,在这个锁被解锁之前,所有试图对这个锁加锁的线程都
会被阻塞。(写锁,阻塞后面的其它读写锁操作)
2)当读写锁在读加锁状态时,所有试图以读模式对它进行加锁的线程都可以得到访问
权,但是以写模式对它进行加锁的线程将会被阻塞。(读锁,阻塞后面的写锁,不阻塞后面的读锁)
3)
2、读写锁机制是由 POSIX 提供的,如果写者没有持有读写锁,那么所有的读者都可
以持有这把锁,而一旦有某个写者阻塞在上锁的时候,那么就由 POSIX 系统来决定是否允许
读者获取该锁 。
二、API
1)初始化和销毁读写锁
初始化的方式:两种
a、通过给一个静态分配的读写锁赋予常量值 PTHREAD_RWLOCK_INITIALIZER 来初始化
b、动态 初始化,调用pthread_rwlock_init(),当线程不再需要读写锁的时候,通过调用
销毁pthread_rwlock_destory()
函数原型如下
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthread_rwlockattr_t *restrict attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
在初始化读写锁的时候,如果attr为空,表示使用默认属性
初始化和销毁的返回值,如果执行成功返回0,出错返回错误码
//使用非默认属性
int pthread_rwlockattr_init(pthread_rwl ockattr_t *attr) ;
int pthread_rwlockattr_destroy(pthread_rwlockatttr_ t *attr);
同样如果调用成功返回0,失败返回错误码
- 获取和释放读写锁
pthread_rwlock_rdlock()用来获取读出锁,如果相应的读出锁已经被某个写入者占有 ,那么就阻塞调
用线程 。
pthread_ rwlock_wrlock()以获取一个写入锁,如果相应 的写入锁已经被其他写人者或者
读出者占有(一个或多个),那么就阻塞该调用线程;
pthread_ rwlock_ unlock(),用来释放一个读出或写入锁
下面是三个函数的函数原型
int pthread_ rwlock_rdlock(pthread_ rwlock_t *rWPtr);
int pthread_ rwlock_wrlock(pthread_ rwlock_ t *rWPtr) ;
int pthread_ rwlock_unlock(pthread_ rwlock_t *rWPtr) ;
这三个函数若调用成功,则返回0,失败则返回错误码
注意的是 , 其中获取锁的两个函数的操作都是阻塞操作,也就是说获取不到锁的话,
那么调用线程不是立即返回,而是阻塞执行
下面是两个非阻塞方式获得读写锁的函数非阻塞方式下获取锁的时候,如果不能马上获取到,就会立 即返回一个 EBUSY 错误提示 ,
而不是把调用线程投入到睡眠等待,函数原型如下
int pthread_ rwlock_ tryrdlock(pthread_ rwlock_ t *rWPtr) ;
int pth read_rwlock_t.rywrlock (pthread_rwlock_t *rWPtr) ;
同样调用成功返回0,调用失败返回错误码
三、读写锁的demo
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#define THREADNUM 5
pthread_rwlock_t rwlock;
void *readers(void *arg)
{
pthread_rwlock_rdlock(&rwlock);
printf("reader %ld got the lock\n", (long)arg);
pthread_rwlock_unlock(&rwlock);
pthread_exit((void*)0);
}
void *writers(void *arg)
{
pthread_rwlock_wrlock(&rwlock);
printf("writer %ld got the lock\n", (long)arg);
pthread_rwlock_unlock(&rwlock);
pthread_exit((void*)0);
}
int main(int argc, char **argv){
int iRet, i;
pthread_t writer_id, reader_id;
pthread_attr_t attr;
int nreadercount = 1, nwritercount = 1;
iRet = pthread_rwlock_init(&rwlock, NULL);
if (iRet)
{
fprintf(stderr, "init lock failed\n");
return iRet;
}
pthread_attr_init(&attr);
/*pthread_attr_setdetachstate用来设置线程的分离状态
也就是说一个线程怎么样终止自己,状态设置为PTHREAD_CREATE_DETACHED
表示以分离状态启动线程*/
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
for(i = 0; i < THREADNUM; i++)
{
if (i % 3)
{
pthread_create(&reader_id, &attr, readers, &nreadercount);
printf("create reader %d\n", nreadercount++);
}
else
{
pthread_create(&writer_id, &attr, writers, &nwritercount);
printf("create writer %d\n", nwritercount++);
}
}
for(int i = 0;i < THREADNUM;i++)
{
int iRet = pthread_attr_destroy(&attr);
if(0 != iRet)
{
printf("pthread_attr_destroy error \n");
}
}
sleep(5);/*sleep是为了等待另外的线程的执行*/
return 0;
}
//运行环境Ununtu
把文件命名为Thread.cpp
编译:g++ -o Thread Thread.cpp -lpthread
运行./Thread