linux线程同步(3)-读写锁

一.概述                                                   

读写锁与互斥量的功能类似,对临界区的共享资源进行保护!互斥量一次只让一个线程进入临界区,读写锁比它有更高的并行性。读写锁有以下特点:

1.如果一个线程用读锁锁定了临界区,那么其他线程也可以用读锁来进入临界区,这样就可以多个线程并行操作。但这个时候,如果再进行写锁加锁就会发生阻塞,写锁请求阻塞后,后面如果继续有读锁来请求,这些后来的读锁都会被阻塞!这样避免了读锁长期占用资源,防止写锁饥饿!

2.如果一个线程用写锁锁住了临界区,那么其他线程不管是读锁还是写锁都会发生阻塞!

二.函数接口                                           

1.创建读写锁

1.1:宏常量初始化

1 pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;

1.2:函数初始化

1 #include <pthread.h>
2
3 int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);

rwlock:读写锁的pthread_rwlock_t结构指针

attr:读写锁的属性结构指针。不需要别的属性默认为NULL。

2.读写锁加锁与解锁

1 #include <pthread.h>
2
3 int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
4 int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
5 int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

rwlock:创建的读写锁指针

3.其他类型的加锁

1 #include <pthread.h>
2 #include <time.h>
3
4
5 int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
6 int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
7
8 int pthread_rwlock_timedrdlock(pthread_rwlock_t *restrict rwlock, const struct timespec *restrict abs_timeout);
9 int pthread_rwlock_timedwrlock(pthread_rwlock_t *restrict rwlock, const struct timespec *restrict abs_timeout);

try类函数加锁:如果获取不到锁,会立即返回错误EBUSY!

timed类函数加锁:如果规定的时间内获取不到锁,会返回ETIMEDOUT错误!

4.销毁读写锁

1 #include <pthread.h>
2
3 int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

三.简单的例子                                        

创建4个线程,2个线程读锁,2个线程写锁,观察4个线程进入临界区的顺序:

 1 /**
 2  * @file pthread_rwlock.c
 3  */
 4
 5 #include <stdio.h>
 6 #include <stdlib.h>
 7 #include <string.h>
 8 #include <unistd.h>
 9 #include <pthread.h>
10
11 /* 初始化读写锁 */
12 pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
13 /* 全局资源 */
14 int global_num = 10;
15
16 void err_exit(const char *err_msg)
17 {
18     printf("error:%s\n", err_msg);
19     exit(1);
20 }
21
22 /* 读锁线程函数 */
23 void *thread_read_lock(void *arg)
24 {
25     char *pthr_name = (char *)arg;
26
27     while (1)
28     {
29         /* 读加锁 */
30         pthread_rwlock_rdlock(&rwlock);
31
32         printf("线程%s进入临界区,global_num = %d\n", pthr_name, global_num);
33         sleep(1);
34         printf("线程%s离开临界区...\n", pthr_name);
35
36         /* 读解锁 */
37         pthread_rwlock_unlock(&rwlock);
38
39         sleep(1);
40     }
41
42     return NULL;
43 }
44
45 /* 写锁线程函数 */
46 void *thread_write_lock(void *arg)
47 {
48     char *pthr_name = (char *)arg;
49
50     while (1)
51     {
52         /* 写加锁 */
53         pthread_rwlock_wrlock(&rwlock);
54
55         /* 写操作 */
56         global_num++;
57         printf("线程%s进入临界区,global_num = %d\n", pthr_name, global_num);
58         sleep(1);
59         printf("线程%s离开临界区...\n", pthr_name);
60
61         /* 写解锁 */
62         pthread_rwlock_unlock(&rwlock);
63
64         sleep(2);
65     }
66
67     return NULL;
68 }
69
70 int main(void)
71 {
72     pthread_t tid_read_1, tid_read_2, tid_write_1, tid_write_2;
73
74     /* 创建4个线程,2个读,2个写 */
75     if (pthread_create(&tid_read_1, NULL, thread_read_lock, "read_1") != 0)
76         err_exit("create tid_read_1");
77
78     if (pthread_create(&tid_read_2, NULL, thread_read_lock, "read_2") != 0)
79         err_exit("create tid_read_2");
80
81     if (pthread_create(&tid_write_1, NULL, thread_write_lock, "write_1") != 0)
82         err_exit("create tid_write_1");
83
84     if (pthread_create(&tid_write_2, NULL, thread_write_lock, "write_2") != 0)
85         err_exit("create tid_write_2");
86
87     /* 随便等待一个线程,防止main结束 */
88     if (pthread_join(tid_read_1, NULL) != 0)
89         err_exit("pthread_join()");
90
91     return 0;
92 }

2个线程函数的临界区里面都sleep(1),测试给足够的时间看其他线程能不能进来。64行,写锁函数里面,sleep(2),因为写锁请求会阻塞后面的读锁,2个写锁一起请求会让读锁饥饿,所以比39行的sleep(1)多一秒!

编译运行:

可以看到,读锁可以一起进入临界区,而写锁在临界区里面等1秒都不会有其他线程能进来!!!

时间: 2024-08-04 13:47:23

linux线程同步(3)-读写锁的相关文章

线程同步——用户模式下线程同步——Slim读写锁实现线程同步

1 //Slim读/写锁实现线程同步 2 SRWlock 的目的和关键段相同:对同一资源进行保护,不让其它线程访问. 3 但是,与关键段不同的是,SRWlock允许我们区分哪些想要读取资源的线程(读取者线程) 4 和哪些想要更新资源值的线程(写入者线程).让所有读取者资源在同一时刻访问共享资源应该是 5 可行的,这是因为仅仅读取资源并不存在破坏数据的风险.只有当写入者线程想要对资源进行更新时才需要同步. 6 这种情况下,写入者线程应该独占资源访问权:任何线程,无论是读取还是写入者线程,都不许访问

使用信号量控制Linux线程同步

线程同步 在现实生活中,有些东西就必须是按顺序执行的,只有我完成了以后,你才能在我的劳动成果上接着干:不能我还没有完成,你就开始干活了.这就是线程同步最直白的解释了. 在进行程序设计时,亦是如此.线程同步,同步的是什么?它同步的是对共享资源(内存区域,公共变量等)或者临界区域的访问.有的时候,这些共享 资源和临界区域,就只能容忍一个线程对它进行操作(读或者写,读操作一般不控制,主要是写操作),这个时候,我们必须要对这些共享资源或者临界区域进行同 步,那么如何对它们进行线程同步呢? 在Linux中

linux线程间同步(1)读写锁

读写锁比mutex有更高的适用性,可以多个线程同时占用读模式的读写锁,但是只能一个线程占用写模式的读写锁. 1. 当读写锁是写加锁状态时,在这个锁被解锁之前,所有试图对这个锁加锁的线程都会被阻塞: 2. 当读写锁在读加锁状态时,所有试图以读模式对它进行加锁的线程都可以得到访问权,但是以写模式对它进行枷锁的线程将阻塞: 3. 当读写锁在读模式锁状态时,如果有另外线程试图以写模式加锁,读写锁通常会阻塞随后的读模式锁请求,这样可以避免读模式锁长期占用,而等待的写模式锁请求长期阻塞: 这种锁适用对数据结

【转】 Linux 线程同步的三种方法

线程的最大特点是资源的共享性,但资源共享中的同步问题是多线程编程的难点.linux下提供了多种方式来处理线程同步,最常用的是互斥锁.条件变量和信号量. 一.互斥锁(mutex) 通过锁机制实现线程间的同步. 初始化锁.在Linux下,线程的互斥量数据类型是pthread_mutex_t.在使用前,要对它进行初始化.静态分配:pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;动态分配:int pthread_mutex_init(pthread_m

linux线程同步(队列方式)

看了一些关于信号量的线程同步方式,今天用了一下. 我对于线程同步一直有疑问,在主线程和子线程处理时间不相同的时候,用这种信号量,如何保证同步. 假如主线程比较快,信号量连加了n个,但是子线程就不断减这个n,减到0.但是如果主线程太快太快,需要停一停,比如缓冲区快溢出了,主线程需要挂起. 由什么来唤醒主线程呢?子线程?不过这样的话,容易造成主线程死锁,或者主和子都卡死. 下面的程序,没有用到信号量同步,信号量只是负责开启子线程而已.主要是队列的实现而已.等我把上面的问题解决完会写上更新的程序. 队

Linux线程同步

线程同步-互斥锁 1.初始化互斥锁pthread_mutex_init() int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); 例: pthread_mutex_t mutex; pthread_mutex_init(&mutex, NULL); 2.锁住互斥锁pthread_mutex_lock() int pthread_mutex_lock(pt

Linux线程同步---信号量

首先讲一下线程同步信号量的几个关键步骤! 1.定义并初始化信号量. (1) sem_t bin_sem; (2)  res = sem_init(&bin_sem,0,0); 详细步骤可以查看man帮助页面 2.使用信号量 (1) 信号量加1操作.sem_post(&bin_sem); (2) 信号量等待并减1操作.sem_wait(&bin_sem); 初始化后一般处于等待状态,执行某个操作后加1,而另个一个操作执行前进行等待操作.如果有多个线程,通常是一个线程进行加1操作,另外

LINUX线程同步初探

0x00.什么是线程同步 同步,又称直接制约关系,是指多个线程(或进程)为了合作完成任务,必须严格按照规定的 某种先后次序来运行 0x01.案例代码 1 void* PthreadFunc(void* argc); 2 int flag_num = 1; 3 4 int main(int argc, char* argv[]) 5 { 6 pthread_t pid; 7 void* ret_val; 8 9 int create_status = pthread_create(&pid, NU

Linux 线程同步的三种方法(互斥锁、条件变量、信号量)

互斥锁 1 #include <cstdio> 2 3 #include <cstdlib> 4 5 #include <unistd.h> 6 7 #include <pthread.h> 8 9 #include "iostream" 10 11 using namespace std; 12 13 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 14 15 int tmp; 16