您的位置:首页 > 理论基础 > 计算机网络

UNIX网络编程——读写锁

2015-11-27 09:41 691 查看
读写锁比起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 1024
static pthread_rwlock_t rwlock;

char work_area[WORK_SIZE];
int time_to_exit;

void *thread_to_read_o(void *arg);//读线程1
void *thread_to_read_t(void *arg);//读线程2
void *thread_to_write_o(void *arg);//写线程1
void *thread_to_write_t(void *arg);//写线程2

int main(int argc, char *argv[])
{
int retval;
//pthread_t用于声明线程ID
pthread_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);
s
4000
leep(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

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: