互斥锁,读写锁
一、线程互斥方式。 —- 互斥锁
1、什么是互斥锁?特点怎么样?
互斥锁是专门用于处理线程之间互斥的一种方式,它有两种:上锁状态/解锁状态。
如果互斥锁处于上锁状态,那么再上锁就会阻塞,直到这把锁解开之后,才能上锁。
如果互斥锁处于解锁状态,那么再解锁依然可以的,不会阻塞。
2、 互斥锁函数接口?
1)定义互斥锁变量 -> 数据类型: pthread_mutex_t
pthread_mutex_t m;
2)初始化互斥锁。 -> pthread_mutex_init() -> man 3 pthread_mutex_init
动态初始化:
头文件:
#include
原型:
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
参数:
mutex:互斥锁变量的地址。
mutexattr:普通属性,填NULL。
返回值:
成功:0
失败:非0
静态初始化:
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
只要把该宏定义赋值给互斥锁变量,就等价于初始化了这把互斥锁。
========================
也就是说:
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
等价于
pthread_mutex_t m;
pthread_mutex_init(&m,NULL);
3)上锁。 -> pthread_mutex_lock() -> man 3 pthread_mutex_lock
头文件:
#include
原型:
int pthread_mutex_lock(pthread_mutex_t *mutex);
参数:
mutex:互斥锁变量的地址。
返回值:
成功:0
失败:非0
4)解锁。 -> pthread_mutex_unlock() -> man 3 pthread_mutex_unlock
头文件:
#include
原型:
int pthread_mutex_unlock(pthread_mutex_t *mutex);
参数:
mutex:互斥锁变量的地址。
返回值:
成功:0
失败:非0
5)销毁互斥锁。 -> pthread_mutex_destroy() -> man 3 pthread_mutex_destroy
头文件:
#include
原型:
int pthread_mutex_destroy(pthread_mutex_t *mutex);
参数:
mutex:互斥锁变量的地址。
返回值:
成功:0
失败:非0
一般地:
多个线程任务都一样的 -> 互斥锁
多个线程任务不一样的 -> 无名信号量
练习1: 使用互斥锁完成5个线程打印helloworld。 -> 多个线程任务都一样的
练习2: 使用互斥锁完成<练习.docx> -> 多个线程任务不一样的
二、线程互斥方式。 — 读写锁
1、互斥锁有什么缺陷?
互斥锁无论是读取共享资源,还是修改共享资源,都要上锁,而且在上锁期间,不能被别的线程上锁。
访问资源(一起读一本书) -> 同时上读锁 -> 读锁就是一把共享锁。
修改资源(一起做一份试卷) -> 不能同时上写锁 -> 写锁就是一把互斥锁。
这把既有读锁,又有写锁的锁,就称之为读写锁。
2、读写锁函数接口?
1)定义一个读写锁变量。 数据类型: pthread_rwlock_t
pthread_rwlock_t rwlock;
2)初始化读写锁? -> pthread_rwlock_init() -> man 3 pthread_rwlock_init
动态初始化:
头文件:
#include
原型:
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,
const pthread_rwlockattr_t *restrict attr);
参数:
rwlock: 读写锁的地址。
attr: 普通属性,填NULL。
返回值:
成功:0
失败:非0
静态初始化:
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
3)读锁上锁。 -> pthread_rwlock_rdlock() -> man 3 pthread_rwlock_rdlock
头文件:
#include
原型:
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
参数:
rwlock: 读写锁的地址。
返回值:
成功:0
失败:非0
4)写锁上锁。 -> pthread_rwlock_wrlock() -> man 3 pthread_rwlock_wrlock
头文件:
#include
原型:
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
参数:
rwlock: 读写锁的地址。
返回值:
成功:0
失败:非0
5)解锁。 -> pthread_rwlock_unlock() -> man 3 pthread_rwlock_unlock
头文件:
#include
原型:
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
参数:
rwlock: 读写锁的地址。
返回值:
成功:0
失败:非0
6)销毁读写锁。 -> pthread_rwlock_destroy() -> man 3 pthread_rwlock_destroy
头文件:
#include
原型:
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
参数:
rwlock: 读写锁的地址。
返回值:
成功:0
失败:非0
练习3: 现有一个临界资源: “int a” -> 全局变量
现在有4个线程,有两个线程想打印a的值 -> 读
thread1: 3S thread2:5S -> 看时间 -> 如果读完需要8S,则读锁不能同时上
有两个线程想修改a的值,一个想改成30,一个想改成50 -> 写
thread3: 4S thread4: 6S
再开一条线程,用于倒数时间就行。
验证:1)读锁可以同时上,写锁不可以同时上。
2)读锁与写锁能不能同时上? -> 不可以,读锁要等到写锁解开了之后才能上锁。
#include “head.h”
int a = 100; //临界资源
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
void *func_time(void *arg)
{
int i;
for(i=0;i<1000;i++)
{
printf(“i = %d\n”,i);
sleep(1);
}
}
//线程1: 打印a的值。 -> 3S (读操作)
void *func1(void *arg)
{
//1. 访问资源前,先上读锁。
pthread_rwlock_rdlock(&rwlock);
printf(“thread 1 rdlock lock!\n”);
//2. 打印a的值。
printf(“a = %d\n”,a);
//3. 持续3S
sleep(3);
//4. 访问完资源了,需要解锁。
pthread_rwlock_unlock(&rwlock);
printf(“thread 1 rdlock unlock!\n”);
//5. 线程退出
pthread_exit(NULL);
}
//线程2: 打印a的值。 -> 5S (读操作)
void *func2(void *arg)
{
//1. 访问资源前,先上读锁。
pthread_rwlock_rdlock(&rwlock);
printf(“thread 2 rdlock lock!\n”);
//2. 打印a的值。
printf(“a = %d\n”,a);
//3. 持续5S
sleep(5);
//4. 访问完资源了,需要解锁。
pthread_rwlock_unlock(&rwlock);
printf(“thread 2 rdlock unlock!\n”);
pthread_exit(NULL);
}
//线程3:修改a的值为50。 -> 4S
void *func3(void *arg)
{
//1. 修改资源之前,需要上写锁。
pthread_rwlock_wrlock(&rwlock);
printf(“thread 3 wrlock lock!\n”);
//2. 修改临界资源。
a = 50;
//3. 持续一段时间。
sleep(4);
//4. 修改资源后,需要解锁。
pthread_rwlock_unlock(&rwlock);
printf(“thread 3 wrlock unlock!\n”);
pthread_exit(NULL);
}
//线程4:修改a的值为30。 -> 6S
void *func4(void *arg)
{
//1. 修改资源之前,需要上写锁。
pthread_rwlock_wrlock(&rwlock);
printf(“thread 4 wrlock lock!\n”);
//2. 修改临界资源。
a = 100;
//3. 持续一段时间。
sleep(6);
//4. 修改资源后,需要解锁。
pthread_rwlock_unlock(&rwlock);
printf(“thread 4 wrlock unlock!\n”);
pthread_exit(NULL);
}
int main(int argc,char *argv[])
{
//0. 创建一个用于倒数时间线程
pthread_t tid_time;
pthread_create(&tid_time,NULL,func_time,NULL);
//1、 创建2个子线程,用于打印临界资源的值。
pthread_t tid1,tid2,tid3,tid4;
pthread_create(&tid1,NULL,func1,NULL);
pthread_create(&tid2,NULL,func2,NULL);
pthread_create(&tid3,NULL,func3,NULL);
pthread_create(&tid4,NULL,func4,NULL);
//2. 接合线程
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
pthread_join(tid3,NULL);
pthread_join(tid4,NULL);
//3. 销毁读写锁
pthread_rwlock_destroy(&rwlock);
return 0;
}
还没有评论,来说两句吧...