线程互斥锁、读写锁、自旋锁、死锁

线程竞争
一、基本概念
    竞争与同步
        同一个进程中的线程共享进程中的绝大多数资源,当它们随意竞争时可能会导致资源被破坏、脏数据、不完整问题
        通过一些手段让线程在竞争资源时相互协调、避免出现以上问题,这就称为线程同步
    原子操作:
        操作过程中不能被打断的操作称为原子操作
    临界资源、临界区、竞态条件:
        能够被多个进程访问但是又无法同时访问的资源称为临界资源
        每个进程中访问临界资源的那段代码称为临界区,能够被多个线程访问但是又无法同时访问的代码片段
        多个线程在临界区内执行时,由于线程的执行顺序具有随机性,从而导致结果不确定,称为发生了竞态条件

二、互斥量(互斥锁)

代码使用:

         int pthread_mutex_init(pthread_mutex_t* mutex,const pthread_mutexattr_t * attr);
    功能:对互斥量进行初始化,完成后锁处于开锁状态
    mutex:要初始化的互斥量
    attr:互斥量的属性设置,一般默认给NULL即可
    
    也可以在定义时通过PTHREAD_MUTEX_INITIALIZER初始化互斥量
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

    int pthread_mutex_lock(pthread_mutex_t *mutex);
    功能:对互斥量加锁,成功则返回继续执行,失败则阻塞休眠等待,直到互斥量解锁并成功加锁才唤醒返回

    int pthread_mutex_unlock(pthread_mutex_t *mutex);
    功能:对互斥量解锁,对别人上锁的互斥量解锁,失败返回EBUSY

    int pthread_mutex_trylock(pthread_mutex_t *mutex);
    功能:对互斥量尝试加锁,成功返回0 失败返回EBUSY,立即返回

    int pthread_mutex_destroy(pthread_mutex_t *mutex);
    功能:销毁互斥量

三、读写锁
    读写锁将线程访问共享数据时发出的请求分为两种:
        读请求:只读取共享数据,不修改
        写请求:存在修改共享数据的行为
        1、当有多个线程同时发出读请求,可以同时执行
        2、当有多个线程同时发出写请求,只能一个一个的执行
        3、当发出读请求的线程正在执行时,发出写请求的线程必须等待前面所有读请求线程执行完后才能执行
        4、当发出写请求的线程正在执行时,发出读请求的线程必须等待前面所有写请求线程执行完后才能执行
    当读写锁被发出读请求的线程占用时,称为"读锁",当读写锁被发出读请求的线程占用时,称为"写锁"
        1、当读写锁未被任何线程占用,发出读请求、写请求的线程都可以占用,如果同时请求,默认优先给读请求占用
        2、当变成读锁(多个线程占用)时,读请求的线程可以占用不会阻塞,但是写请求的线程会阻塞等待读锁解锁
        3、当变成写锁(单个线程占用)时,读、写请求的线程都会阻塞等待写锁解锁

        pthread_rwlock_init 初始化读写锁
        pthread_rwlock_wrlock 写锁上锁
        pthread_rwlock_rdlock 读锁上锁
        pthread_rwlock_unlock 解锁
        pthread_rwlock_destroy 销毁
    
四、自旋锁
    在任意时刻最多只能有一个线程获取该锁
    对于互斥量,如果资源已经被占用,申请者会进入休眠态
    对于自旋锁,则不会引起申请者休眠,而是一直在申请处进入循环不停地查看自旋锁是否解锁,直到解锁并加锁成功后才退出循环往下执行
    一般情况下使用互斥量,但是如果知道被锁住的代码执行时间很多(或者是主动让其变短),那么应该选择使用系统开销(运行态<->休眠态)较少的自旋锁更合适

五、死锁
    1、什么是死锁
        多个进程或线程相互等待对方的资源,在得到新资源前不会释放自己的旧资源,这样就形成了循环等待,该现象称为死锁
    2、产生死锁的四大必要条件
        资源互斥:资源只有两种状态,可用和不可用,资源不能被同时使用,同一时刻只能被一个进程或线程使用
        占用且请求:已经得到资源的进程或线程,会继续请求新的资源,并且持续占用旧资源
        资源不可剥夺:当资源已经分配给进程或线程后,不能被其他进程或线程强制性获取,除非占用者主动释放
        环路等待:死锁发生时,系统中必定有两个或以上的进程或线程的执行路线形成等待环路
        注意:一旦产生死锁基本无解,现在的操作系统无法解决死锁,因此只能防止死锁的产生
    3、防止死锁产生的方法
        破坏互斥条件:
            想办法让资源能够共享
            缺点:受到环境或资金的影响无法让资源共享
        破坏占用且请求:
            采用静态预分配的方式,进程或线程在运行前尝试一次性申请所有的资源,在资源没有得到全部满足不投入运行
            缺点:可能会导致系统资源的昂费,因为有些资源是很靠后才会使用,但是已经提前分配占用,导致其它不会产生死锁的进程或线程也无法使用
        破坏资源不可剥夺:
            当一个进程或线程占用了不可被剥夺的资源,并且请求新资源无法得到满足时,那么就把全部占用的资源主动释放,过一段时间后重新开始
            缺点:该策略实现难度高,释放已经占用的资源会导致前一阶段的工作失效,还要反复申请释放资源,浪费资源、时间
        破坏环路等待:
            给每个资源进行编号,进程或线程都按照编号顺序来请求资源,并且必须拿到前一个编号资源后,才能去拿后一个
            缺点:资源的编号顺序要相对稳定,否则在运行期间资源的增加或删减都会让该过程受极大的影响
    4、如何判断死锁
        1、画出资源分配图
        2、简化资源分配图
        3、使用死锁定理判断:看有没有环路

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值