计算机操作系统基础(十二)---线程同步之自旋锁

引言

本文为第十二篇,线程同步之自旋锁,在上一篇文章介绍了互斥量,通过互斥量解决线程同步的问题。本文是另一个解决线程同步的方法—自旋锁

自旋锁

自旋锁的工作原理跟互斥量的工作原理其实是一模一样的,它也是在访问临界资源之前加一个锁,完成之后再将锁给释放掉。但是互斥量和自旋锁还是有一点区别的

  • 自旋锁也是一种多线程同步的变量
  • 使用了自旋锁的线程会反复检查锁变量是否可用,如果不可用就会循环反复的检查
  • 因此自旋锁不会让出CPU,是一种忙等待状态

因此自旋锁其实就是:死循环等待锁被释放

自旋锁好处

  • 自旋锁避免了进程或线程上下文切换的开销(如果这个锁占用的时间不是很长,这个代价还是很小的)
  • 操作系统内部很多地方都是使用自旋锁,而不是互斥量
  • 自旋锁不适合在单核CPU使用(因为自旋锁在等待的时候并不会释放CPU,如果在单核CPU使用的话会引起其它的进程或线程无法执行)

自旋锁和互斥量(锁)的比较

  • 自旋锁是一种非阻塞锁,也就是说,如果某线程需要获取自旋锁,但该锁已经被其他线程占用时,该线程不会被挂起,而是在不断的消耗CPU的时间,不停的试图获取自旋锁
  • 互斥量是阻塞锁,当某线程无法获取互斥量时,该线程会被直接挂起,该线程不再消耗CPU时间,当其他线程释放互斥量后,操作系统会激活那个被挂起的线程,让其投入运行

两种锁适用的场景

  • 如果是多核处理器,如果预计线程等待锁的时间很短,短到比线程两次上下文切换时间要少的情况下,使用自旋锁是划算的
  • 如果是多核处理器,如果预计线程等待锁的时间较长,至少比两次线程上下文切换的时间要长,建议使用互斥量
  • 如果是单核处理器,一般建议不要使用自旋锁。因为,在同一时间只有一个线程是处在运行状态,那如果运行线程发现无法获取锁,只能等待解锁,但因为自身不挂起,所以那个获取到锁的线程没有办法进入运行状态,只能等到运行线程把操作系统分给它的时间片用完,才能有机会被调度。这种情况下使用自旋锁的代价很高

建议:如果加锁的代码经常被调用,但竞争情况很少发生时,应该优先考虑使用自旋锁,自旋锁的开销比较小,互斥量的开销较大

自旋锁的代码示例

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
$include<vector>

//自旋锁定义
pthread_spinlock_t spin_lock;

//临界资源
int num=0;

//生产者
void *producer(void*){
        int times = 100000000;//循环一百万次
        while(times--){
                //加自旋锁
              pthread_spin_lock(&spin_lock);
                num += 1;//每次生产一个产品
                //解锁
            pthread_spin_unlock(&spin_lock);
        }
}

//消费者
void *consumer(void*){
        int times = 100000000;
        while(times--){
              //加自旋锁
              pthread_spin_lock(&spin_lock);
                num -= 1;//每次消费一个产品
                //解锁
            pthread_spin_unlock(&spin_lock);
        }
}

int main()
{
        printf("Start in main function.");
        //初始化自旋锁
        pthread_spin_init(&spin_lock, 0);
        //定义两个线程
        pthread_t thread1,thread2;
        //一个执行生成者逻辑,一个执行消费者逻辑
        pthread_create(&thread1, NULL, &producer, NULL);
        pthread_create(&thread2, NULL, &consumer, NULL);
        pthread_join(&thread1, NULL);
        pthread_join(&thread2, NULL);
        //打印临界资源的值
        printf("Print in main function: num = %d\n", num);
        return 0;
}

执行结果

在快速变化的技术中寻找不变,才是一个技术人的核心竞争力。知行合一,理论结合实践

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值