Linux下用mutex和cond实现读写锁

来源:互联网 发布:regina知乎 编辑:程序博客网 时间:2024/06/04 18:22

Linux下使用mutex和cond实现读写锁

1 首先 介绍下pthread_cond_t。 在Linux下称之为状态变量,与之相关的有下面几个API:

int pthread_cond_init (pthread_cond_t *COND,pthread_condattr_t *cond_ATTR);int pthread_cond_signal (pthread_cond_t *COND);int pthread_cond_broadcast (pthread_cond_t *COND);int pthread_cond_wait (pthread_cond_t *COND, pthread_mutex_t *MUTEX);int pthread_cond_timedwait (pthread_cond_t *COND, pthread_mutex_t *MUTEX, const struct timespec *ABSTIME);int pthread_cond_destroy (pthread_cond_t *COND);

这里就讲下2个api,pthread_cond_signal和pthread_cond_wait,一般的用法如下:

{    pthread_mutex_lock(lock) ...    pthread_cond_wait(cond, lock); ...    pthread_cond_mutex_unlock(lock);}

pthread_cond_wait会解锁lock,然后在cond上等待,这两步是atomic operation. 当pthread_cond_wait返回时,会同时对lock解锁。

{    pthread_mutex_lock(lock); ...    pthread_cond_signal(cond); ...    pthread_mutex_unlock(lock);}

read_cond_signal调用之前一定会先拿到lock锁。pthread_cond_signal不会去管lock锁,只是将cond激活,接下去释放lock锁。这时候pthread_cond_wait就可以等到cond从而返回了。
2 其次 ,讲一下读写锁和互斥量的不同特性。
互斥量Mutex,它只有两个状态,要么是加锁状态,要么是不加锁。假如现在一个线程 a 只想读一个共享变量 i ,因为不确定是否会有线程去写他,所以我们还是要对它进行加锁。但是这时候又一个线程 b 试图读共享变量i ,于是发现被锁住,那么b不得不等到a释放了锁后才能获得锁并读取 i 的值,
但是两个读取操作即使是几乎同时发生也并不会像写操作那样造成竞争,应为他们不修改变量的值。所以我们期望如果是 多个线程试图读取共享变量的 值的话,那么他们应该可以立刻获取而不需要等待前一个线程释放因为读而加的锁。
读写锁解决了上面的问题。他提供了比互斥量更好的并行性。因为以读模式加锁后当又有多个线程仅仅是试图再以读模式加锁然时,并不会造成这些线程阻塞在等待锁的释放上。
读写锁的特点:
1)多个读者可以同时进行读。
2)写者必须互斥(只允许一个写者写,也不能读者写者同时进行)。
3)写者优先于读者(一旦有写者,则后续读者必须等待,唤醒时优先考虑写者)。

3 最后 ,下面是利用条件变量cond和互斥量mutex实现的一个读写锁的例子:

typedef struct pthread_rwlock{    int active_readers; /* -1 when writer lock locked, >0 when read lock locked */    int pending_readers;    int pending_writers;    pthread_mutex_t mutex;    pthread_cond_t ok_to_read;    pthread_cond_t ok_to_write;} pthread_rwlock_t ;int pthread_rwlock_init(pthread_rwlock_t * lock, pthread_rwlockattr_t *attr){    active_readers = 0;    pending_readers = 0;    pending_writers = 0;    pthread_mutex_init(&lock->mutex, NULL);    pthread_cond_init(&lock->ok_to_read, NULL);    pthread_cond_init(&lock->ok_to_write, NULL);    return 0;}int pthread_rwlock_destroy(pthread_rwlock_t * lock) {    pthread_mutex_destroy(&lock->mutex);    pthread_cond_destroy(&lock->ok_to_read);    pthread_cond_destroy(&lock->ok_to_write);    return 0;}int pthread_rwlock_rdlock(pthread_rwlock_t * lock) {    pthread_mutex_lock(&lock->mutex);    lock->pending_readers++;    while(lock->active_readers < 0) /* the write lock locked */{        pthread_cond_wait(&lock->ok_to_read, &lock->mutex);    }    lock->pending_readers--;    lock->active_readers++;    pthread_mutex_unlock(&lock->mutex);    return 0;}int pthread_rwlock_tryrdlock(pthread_rwlock_t * lock) {    if(pthread_mutex_trylock(&lock->mutex) == EBUSY)    {        return -1;    }    if(lock->active_readers < 0) /* the write lock locked */    {        pthread_mutex_unlock(&lock->mutex);        return -1;    }    lock->active_readers++;    pthread_mutex_unlock(&lock->mutex);    return 0;}int pthread_rwlock_wrlock(pthread_rwlock_t * lock){    pthread_mutex_lock(&lock->mutex);    lock->pending_writers++;    while(lock->active_readers) /* the write lock or read lock locked */{        pthread_cond_wait(&lock->ok_to_write, &lock->mutex);    }     lock->pending_writers--;     lock->active_readers = -1;     pthread_mutex_unlock(&lock->mutex);     return 0;}int pthread_rwlock_trywrlock(pthread_rwlock_t * lock){    if(pthread_mutex_trylock(&lock->mutex) == EBUSY)    {        return -1;    }    if(lock->active_readers) /* the write lock or read lock locked */    {        pthread_mutex_unlock(&lock->mutex);        return  -1;    }     lock->active_readers = -1;     pthread_mutex_unlock(&lock->mutex);     return 0;}int pthread_rwlock_unlock(pthread_rwlock_t * lock){    pthread_mutex_lock(&lock->mutex);    assert(lock->active_readers);//unlock的时候active_readers不能为0    if (lock->active_readers > 0) /* release the read lock */     {          lock->active_readers--;          if (lock->active_readers == 0) /* no read lock locked */          {             pthread_cond_signal(&lock->ok_to_write);          }     } else if (lock->active_readers < 0) /* release the write lock */     {         lock->active_readers=0;          /* it may be different, when write lock has higher priority than read lock */          if (lock->pending_readers > 0) {               pthread_cond_broadcast(&lock->ok_to_read);          } else if (lock->pending_writers > 0) {               pthread_cond_signal(&lock->ok_to_write);          }     }     pthread_mutex_unlock(&lock->mutex);     return 0;}
1 0