UNIX网络编程——读写锁

来源:互联网 发布:d3.js官网是什么 编辑:程序博客网 时间:2024/05/29 23:48
读写锁比起mutex具有更高的适用性,具有更高的并行性,可以有多个线程同时占用读模式的读写锁,但是只能有一个线程占用写模式的读写锁,读写锁的三种状态:
1.当读写锁是写加锁状态时,在这个锁被解锁之前,所有试图对这个锁加锁的线程都会被阻塞
2.当读写锁在读加锁状态时,所有试图以读模式对它进行加锁的线程都可以得到访问权,但是以写模式对它进行加锁的线程将会被阻塞

3.当读写锁在读模式的锁状态时,如果有另外的线程试图以写模式加锁,读写锁通常会阻塞随后的读模式锁的请求,这样可以避免读模式锁长期占用,而等待的写模式锁请求则长期阻塞。

读写锁相关的API
1.初始化和销毁读写锁
    对于读写锁变量的初始化可以有两种方式,一种是通过给一个静态分配的读写锁赋予常值PTHREAD_RWLOCK_INITIALIZER来初始化它,另一种方法就是通过调用pthread_rwlock_init()来动态的初始化。而当某个线程不再需要读写锁的时候,可以通过调用pthread_rwlock_destroy来销毁该锁。函数原型如下:
#include 
int pthread_rwlock_init(pthread_rwlock_t *rwptr, const pthread_rwlockattr_t *attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwptr);
这两个函数如果执行成功均返回0,如果出错则返回错误码。
在释放某个读写锁占用的内存之前,要先通过pthread_rwlock_destroy对读写锁进行清理,释放由pthread_rwlock_init所分配的资源。
在初始化某个读写锁的时候,如果属性指针attr是个空指针的话,表示默认的属性;如果想要使用非默认属性,则要使用到下面的两个函数:
#include 
int pthread_rwlockattr_init(pthread_rwlockattr_t *attr);
int pthread_rwlockattr_destroy(pthread_rwlockatttr_t *attr);
这两个函数同样的,如果执行成功返回0,失败返回错误码。
这里还需要说明的是,当初始化读写锁完毕以后呢,该锁就处于一个非锁定状态。
数据类型为pthread_rwlockattr_t的某个属性对象一旦初始化了,就可以通过不同的函数调用来启用或者是禁用某个特定的属性。
2.获取和释放读写锁
读写锁的数据类型是pthread_rwlock_t,如果这个数据类型中的某个变量是静态分配的,那么可以通过给它赋予常值PTHREAD_RWLOCK_INITIALIZAR来初始化它。pthread_rwlock_rdlock()用来获取读出锁,如果相应的读出锁已经被某个写入者占有,那么就阻塞调用线程。pthread_rwlock_wrlock()用来获取一个写入锁,如果相应的写入锁已经被其它写入者或者一个或多个读出者占有,那么就阻塞该调用线程;pthread_rwlock_unlock()用来释放一个读出或者写入锁。函数原型如下:
#include 
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,失败就返回错误码。要注意的是其中获取锁的两个函数的操作都是阻塞操作,也就是说获取不到锁的话,那么调用线程不是立即返回,而是阻塞执行。有写情况下,这种阻塞式的获取所得方式可能不是很适用,所以,接下来引入两个采用非阻塞方式获取读写锁的函数pthread_rwlock_tryrdlock()和pthread_rwlock_trywrlock(),非阻塞方式下获取锁的时候,如果不能马上获取到,就会立即返回一个EBUSY错误,而不是把调用线程投入到睡眠等待。函数原型如下:
#include 
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwptr);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwptr);
同样地,这两个函数调用成功返回0,失败返回错误码。

看一个读写操作:

/*pthread_rwlock_test1.c说明: *使用读写锁实现四个线程读写一段程序的实例,共创建了四个新的线程,其中两个线程用来读取 *数据,另外两个线程用来写入数据。在任意时刻,如果有一个线程在写数据,将阻塞所有其他线 *程的任何操作 * */#include <stdio.h>#include <pthread.h>#include <stdlib.h>#include <bits/pthreadtypes.h>#include<unistd.h>#define WORK_SIZE 1024static pthread_rwlock_t rwlock;char work_area[WORK_SIZE];int time_to_exit;void *thread_to_read_o(void *arg);//读线程1void *thread_to_read_t(void *arg);//读线程2void *thread_to_write_o(void *arg);//写线程1void *thread_to_write_t(void *arg);//写线程2int main(int argc, char *argv[]){int retval;//pthread_t用于声明线程IDpthread_t a_thread, b_thread, c_thread, d_thread;void *thread_result;retval = pthread_rwlock_init(&rwlock, NULL);if (retval != 0) {perror("rwlock initialization failed\n");exit(EXIT_FAILURE);}retval = pthread_create(&a_thread, NULL, thread_to_read_o, NULL);//创建一个新线程if (retval != 0) {perror("thread create failed\n");exit(EXIT_FAILURE);}retval = pthread_create(&b_thread, NULL, thread_to_read_t, NULL);if (retval != 0) {perror("thread create failed\n");exit(EXIT_FAILURE);}retval = pthread_create(&c_thread, NULL, thread_to_write_o, NULL);if (retval != 0) {perror("thread create failed\n");exit(EXIT_FAILURE);}retval = pthread_create(&d_thread, NULL, thread_to_write_t, NULL);if (retval != 0) {perror("thread create failed\n");exit(EXIT_FAILURE);}retval = pthread_join(a_thread, &thread_result);if (retval != 0) {perror("thread join failed\n");exit(EXIT_FAILURE);}retval = pthread_join(b_thread, &thread_result);if (retval != 0) {perror("thread join failed\n");exit(EXIT_FAILURE);}retval = pthread_join(c_thread, &thread_result);if (retval != 0) {perror("thread join failed\n");exit(EXIT_FAILURE);}retval = pthread_join(d_thread, &thread_result);if (retval != 0) {perror("thread join failed\n");exit(EXIT_FAILURE);}pthread_rwlock_destroy(&rwlock); //销毁读写锁exit(EXIT_FAILURE);}void *thread_to_read_o(void *arg){printf("thread read one try to get lock\n");pthread_rwlock_rdlock(&rwlock);//获取读取锁while (strncmp("end", work_area, 3) != 0) {printf("this is thread read one\n");printf("the characters is %s", work_area);pthread_rwlock_unlock(&rwlock);sleep(2);pthread_rwlock_rdlock(&rwlock);while (work_area[0] == '\0') {pthread_rwlock_unlock(&rwlock);sleep(2);pthread_rwlock_rdlock(&rwlock);}}pthread_rwlock_unlock(&rwlock);time_to_exit = 1;pthread_exit(0);}void *thread_to_read_t(void *arg){printf("thread read two try to get lock\n");pthread_rwlock_rdlock(&rwlock);while (strncmp("end", work_area, 3) != 0) {printf("this is thread read two\n");printf("the characters is %s\n", work_area);pthread_rwlock_unlock(&rwlock);sleep(5);pthread_rwlock_rdlock(&rwlock);while (work_area[0] == '\0') {pthread_rwlock_unlock(&rwlock);sleep(5);pthread_rwlock_rdlock(&rwlock);}}pthread_rwlock_unlock(&rwlock);time_to_exit = 1;pthread_exit(0);}void *thread_to_write_o(void *arg){printf("this is write thread one try to get lock\n");while (!time_to_exit) {pthread_rwlock_wrlock(&rwlock);printf("this is write thread one\n. Input some text. Enter 'end' to finish\n");fgets(work_area, WORK_SIZE, stdin);pthread_rwlock_unlock(&rwlock);sleep(15);}pthread_rwlock_unlock(&rwlock);pthread_exit(0);}void *thread_to_write_t(void *arg){sleep(10);while (!time_to_exit) {pthread_rwlock_wrlock(&rwlock);printf("this is write thread two\nInput some text.Enter 'end' to finish\n");fgets(work_area, WORK_SIZE, stdin);pthread_rwlock_unlock(&rwlock);sleep(20);}pthread_rwlock_unlock(&rwlock);pthread_exit(0);}
编译: g++ -o test lock_read_write.cpp -lrt -lpthread

当输入“end”的时候结束输入线程,这里各个线程之间的时间要控制的比较好才行。

代码原文:http://blog.chinaunix.net/uid-27177626-id-3791049.html


  



0 0