互斥锁,读写锁

本文详细介绍了线程互斥的两种方式:互斥锁和读写锁。通过实例演示了如何使用互斥锁实现多线程同步,以及读写锁在读写操作中的应用,强调了互斥锁在读取和修改资源时的互斥特性,而读写锁允许多个线程同时读取但仅允许一个线程写入。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、线程互斥方式。  ---  互斥锁
1、什么是互斥锁?特点怎么样?
互斥锁是专门用于处理线程之间互斥的一种方式,它有两种:上锁状态/解锁状态。
如果互斥锁处于上锁状态,那么再上锁就会阻塞,直到这把锁解开之后,才能上锁。
如果互斥锁处于解锁状态,那么再解锁依然可以的,不会阻塞。

2、 互斥锁函数接口?
1)定义互斥锁变量   -> 数据类型: pthread_mutex_t
   pthread_mutex_t m;

2)初始化互斥锁。  -> pthread_mutex_init()  -> man 3 pthread_mutex_init
动态初始化:
头文件:
    #include <pthread.h>

原型:
      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 <pthread.h>

原型:
    int pthread_mutex_lock(pthread_mutex_t *mutex);

参数:
    mutex:互斥锁变量的地址。

返回值:
    成功:0
    失败:非0

4)解锁。  -> pthread_mutex_unlock()  -> man 3 pthread_mutex_unlock
头文件:
    #include <pthread.h>

原型:
    int pthread_mutex_unlock(pthread_mutex_t *mutex);

参数:
    mutex:互斥锁变量的地址。

返回值:
    成功:0
    失败:非0

5)销毁互斥锁。   -> pthread_mutex_destroy()  -> man 3 pthread_mutex_destroy
头文件:
    #include <pthread.h>

原型:
    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 <pthread.h>

原型:
    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 <pthread.h>

原型:
    int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

参数:
    rwlock: 读写锁的地址。

返回值:
    成功:0
    失败:非0

4)写锁上锁。  -> pthread_rwlock_wrlock()   -> man 3 pthread_rwlock_wrlock
头文件:
    #include <pthread.h>
原型:
       int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

参数:
    rwlock: 读写锁的地址。

返回值:
    成功:0
    失败:非0

5)解锁。  -> pthread_rwlock_unlock()  -> man 3 pthread_rwlock_unlock
头文件:
    #include <pthread.h>

原型:
       int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

参数:
    rwlock: 读写锁的地址。

返回值:
    成功:0
    失败:非0

6)销毁读写锁。  -> pthread_rwlock_destroy()  -> man 3 pthread_rwlock_destroy
头文件:
    #include <pthread.h>
原型:
    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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值