Linux进/线程同步方式3——自旋锁
创始人
2024-09-25 16:22:16
0

一、自旋锁的背景和定义

  • 自旋锁是为实现保护共享资源而提出的一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁还是自旋锁,在任何时刻,最多只能有一个保持者,也就是说,在任何时刻最多只能有一个执行单元获得锁。
  • 两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠。如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁(忙循环)。

二、自旋锁的适用情况

  • 自旋锁比较适用于锁使用者保持锁时间比较短的情况。也正是由于自旋锁使用者一般保持锁时间非常短,自旋锁的效率远高于互斥锁。
  • 信号量和读写信号量适合于保持时间较长的情况,它们会导致调用者睡眠,因此只能在进程上下文使用,而自旋锁适合于保持时间非常短的情况,它可以在任何上下文中使用。如果被保护的共享资源只在进程上下文中访问,使用信号量保护该共享资源非常合适,如果对共享资源的访问时间非常短,自旋锁也可以。
  • 自旋锁保持期间是抢占失效的,而信号量和读写信号量保持期间是可以被抢占的。
    • 单CPU非抢占内核下:自旋锁会退化成开关中断(因为单CPU且非抢占模式情况下,不可能发生进程切换,时钟只有一个进程处于临界区,自旋锁实际没什么用了)。当获取自旋锁时就是关闭中断,释放自旋锁就是开启中断。因此通过自旋锁可以防止中断打断进程运行。
    • 单CPU抢占内核下:自选锁会被当作一个设置抢占的开关以及开关中断的开关(因为单CPU不可能有并发访问临界区的情况,禁止抢占就可以保证临街区唯一被拥有)。中断是和上述同样的道理。
    • 多CPU下:此时才能完全发挥自旋锁的作用,自旋锁在内核中主要用来防止多处理器中并发访问临界区,防止内核抢占造成的竞争。
  • 操作是原子的,因为当有多个线程在自旋时,也只能有一个线程可以获得该锁。

三、自旋锁的几个重要特性

  1. 被自旋锁保护的临界区代码执行时不能进入休眠;
  2. 被自旋锁保护的临界区代码执行时不能被其他中断打断;
  3. 被自旋锁保护的临界区代码执行时,内核不能被抢占;
  4. 在自旋锁忙等待期间因为并没有进入临界区,所以内核还是可以抢占的。因此,等待自旋锁释放的进程有可能被更高优先级的进程所抢占。
  5. 存在两个问题:死锁和过多占用CPU资源。
    从这几个特性可以归纳出一个共性:被自旋锁保护的临界区代码执行时,它不能因为任何原因放弃处理器。

四、如何避免死锁

  1. 如果中断处理函数中也要获得自旋锁,那么驱动程序需要在拥有自旋锁时禁止中断;
  2. 自旋锁必须在尽可能短的时间内被持有;
  3. 避免某个获得锁的函数调用其他同样试图获取这个锁的函数,否则代码就会死锁;不论是信号量还是自旋锁,都不允许锁拥有者第二次获得这个锁,如果试图这么做,系统将挂起。

五、自旋锁相关的API函数

  1. 初始化
    当线程使用该函数初始化一个未初始化或被销毁过的自旋锁时有效。该函数会为自旋锁申请资源并且初始化为unlocked状态。
    int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
    若成功,返回0;否则,返回错误编号。
    • pthread_spinlock_t:待初始化的自旋锁
    • pshared:
      • PTHREAD_PROCESS_SHARED:该自旋锁可以在多个进程中的线程之间共享(可以被其他进程中的线程看到)。
      • PTHREAD_PROCESS_PRIVATE:仅初始化本自旋锁的线程所在的进程内的线程才能够使用该自旋锁。
  2. 加锁
    用来获取指定的自旋锁,如果该自旋锁当前没有被其他线程所持有,则调用该函数的线程就可以获得该自旋锁,否则该函数在获得自旋锁之前不会返回,一直处于自旋等待状态。
    int pthread_spin_lock(pthread_spinlock_t *lock);
    若成功,返回0;否则,返回错误编号。
  3. 解锁
    释放线程正在持有的自旋锁。
    int pthread_spin_unlock(pthread_spinlock_t *lock);
    若成功,返回0;否则,返回错误编号。
  4. 销毁
    用来销毁指定的自旋锁并释放所有相关联的资源。
    int pthread_spin_destroy(pthread_spinlock_t *lock);
    若成功,返回0;否则,返回错误编号。
    • 在调用该函数之后如果没有调用pthread_spin_init重新初始化自旋锁,则任何尝试使用该锁的调用结果都是未定义的。
    • 如果调用该函数时自旋锁正在被使用或者自旋锁未被初始化则结果是未定义的。

六、自旋锁和互斥锁对比

  • Mutex(互斥锁)
    • sleep-waiting类型的锁
    • 与自旋锁相比它需要消耗大量的系统资源来建立锁,随后当线程被阻塞时,线程的调度状态被修改,并且线程被加入等待线程队列;最后当锁可用时,在获取锁之前,线程会被从等待队列取出并更改其调度状态;但是在线程被阻塞期间,它不消耗CPU资源。
    • 互斥锁适用于那些可能会阻塞很长时间的场景。
      • 1、临界区有IO操作
      • 2、临界区代码复杂或者循环量大
      • 3、临界区竞争非常激烈
      • 4、单核处理器
  • Spin lock(自旋锁)
    • busy-waiting类型的锁
    • 对于自旋锁来说,它只需要消耗很少的资源来建立锁,随后当线程被阻塞时,它就会一直重复检查看锁是否可用了,也就是说当自旋锁处于等待状态时它会一直消耗CPU时间。
    • 自旋锁适用于那些仅需要阻塞很短时间的场景。

七、自旋锁和互斥锁运行实验对比

  • 互斥锁运行实验
    #include  #include  #include  #include   static unsigned int num = 0; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;  /*在sys/time.h中定义的*/ // typedef struct timeval // { //     long tv_sec;     //秒 //     long tv_usec;  //微秒 // }timeval;  __int64_t get_current_timestamp() {     struct timeval now = {0, 0};      gettimeofday(&now, NULL);     return now.tv_sec * 1000 * 1000 + now.tv_usec; }  void thread_proc() {     for(int i = 0; i < 1000000; ++i)     {         pthread_mutex_lock(&mutex);         ++num;         pthread_mutex_unlock(&mutex);     } }  int main() {     pthread_t  t1, t2;     __int64_t start = get_current_timestamp();     pthread_create(&t1, NULL, (void*)thread_proc, NULL);     pthread_create(&t2, NULL, (void*)thread_proc, NULL);     pthread_join(t1, NULL);     pthread_join(t2, NULL);     printf("num:%d\n", num);     __int64_t end = get_current_timestamp();     printf("cost:%ld\n", end - start);     pthread_mutex_destroy(&mutex);      return 0; } 
  • 自旋锁运行实验
    #include  #include  #include  #include   static unsigned int num = 0; pthread_spinlock_t spin_lock;  /*在sys/time.h中定义的*/ // typedef struct timeval // { //     long tv_sec;     //秒 //     long tv_usec;  //微秒 // }timeval;  __int64_t get_current_timestamp() {     struct timeval now = {0, 0};      gettimeofday(&now, NULL);     return now.tv_sec * 1000 * 1000 + now.tv_usec; }  void thread_proc() {     for(int i = 0; i < 1000000; ++i)     {         pthread_spin_lock(&spin_lock);         ++num;         pthread_spin_unlock(&spin_lock);     } }  int main() {     pthread_t  t1, t2;     pthread_spin_init(&spin_lock, PTHREAD_PROCESS_PRIVATE);     __int64_t start = get_current_timestamp();     pthread_create(&t1, NULL, (void*)thread_proc, NULL);     pthread_create(&t2, NULL, (void*)thread_proc, NULL);     pthread_join(t1, NULL);     pthread_join(t2, NULL);     printf("num:%d\n", num);     __int64_t end = get_current_timestamp();     printf("cost:%ld\n", end - start);     pthread_spin_destroy(&spin_lock);      return 0; } 
    在这里插入图片描述
    修改临界区的代码,使得临界区耗时更长:
    void thread_proc() {     for(int i = 0; i < 1000000; ++i)     {         pthread_spin_lock(&spin_lock);         for(int j = 0; j < 1000; ++j)         {              ++num;         }         pthread_spin_unlock(&spin_lock);     } } 
    在这里插入图片描述
    修改以后可以看出自旋锁运行效率慢一些,自旋锁虽然比互斥锁的性能更好(花费很少的CPU指令),但是它只适用于临界区运行时间很短的场景。

相关内容

热门资讯

安卓系统为什么不封闭,揭秘安卓... 你有没有想过,为什么安卓系统那么开放,却不像苹果iOS那样封闭呢?这背后可是有着不少有趣的故事和原因...
安卓系统更新包多大,解析不同版... 你有没有发现,每次安卓系统更新,手机里都会多出那么几个G的文件?这可真是让人好奇,安卓系统更新包究竟...
安卓手机安装双系统吗,安卓手机... 你有没有想过,你的安卓手机是不是也能像电脑一样,装上两个系统,一个用来工作,一个用来娱乐?没错,这就...
oppo会升级安卓系统,畅享最... 你知道吗?最近有个大消息在手机圈里炸开了锅,那就是OPPO要升级安卓系统啦!这可不是什么小打小闹的更...
安卓系统上安装windows,... 你有没有想过,在安卓手机上安装Windows系统?听起来是不是有点不可思议?但你知道吗,这竟然是可能...
安卓系统怎么进运行框,安卓系统... 你有没有想过,你的安卓手机里有一个超级实用的功能,那就是运行框!它就像是一个小助手,帮你快速找到正在...
安卓系统电视无图像设置,安卓电... 你家的安卓系统电视突然没图像了?别急,让我来给你支个招,让你轻松解决这个问题!一、检查电源和连接线首...
安卓机建议升级系统吗,提升性能 你有没有发现,你的安卓手机最近有点儿慢吞吞的?是不是在犹豫要不要升级系统呢?别急,让我来给你好好分析...
升级不了安卓系统升级,探寻升级... 你有没有遇到过这种情况?手机里的安卓系统突然告诉你,它需要升级,但你左等右等,就是升不上去。这可真是...
备用安卓系统手机推荐,盘点热门... 你有没有想过,如果你的手机突然罢工了,你会怎么办?别担心,今天我就要给你安利几款备用安卓系统手机,让...
旧安卓系统ipad无法更新系统... 你有没有遇到过这种情况?你的旧安卓系统iPad突然告诉你,它无法更新系统了!是不是瞬间感觉心里有点小...
运行安卓6系统命令大全,全面掌... 你有没有想过,你的安卓手机里隐藏着无数强大的功能,只等着你去发现和探索呢?今天,就让我带你走进安卓6...
安卓系统简笔画教程下载,轻松绘... 你有没有想过,用简单的线条就能把复杂的安卓系统画出来?没错,就是那种一看就懂,一画就上手的感觉!今天...
华为如何鸿蒙转安卓系统,轻松实... 你知道吗?最近华为的大动作可是让整个科技圈都沸腾了!他们竟然把鸿蒙系统转到了安卓系统上,这可真是让人...
安卓10系统的问题,安卓10系... 你有没有发现,自从你的手机升级到安卓10系统后,好像有点不对劲呢?别急,让我来给你细细道来,看看安卓...
安卓系统苹果搞笑视频,苹果搞笑... 你知道吗?在互联网的世界里,搞笑视频可是个永恒的热门话题。尤其是那些结合了安卓系统和苹果手机的搞笑片...
卡片机改造安卓系统,探索改造之... 你有没有想过,那些曾经陪伴我们记录美好时光的卡片机,现在竟然也能焕发第二春呢?没错,就是那些小巧便携...
装安卓系统倒车出不来,智能科技... 你有没有遇到过这样的事情:手机装了个安卓系统,结果倒车的时候出不来啦?这可不是闹着玩的,简直让人抓狂...
定制安卓系统哪家好点儿,哪家服... 你有没有想过,手机系统就像是个人的衣服,每个人都需要找到最适合自己的那一款?今天,咱们就来聊聊定制安...
台电用回安卓系统吗,开启智能新... 最近有个话题在科技圈里炒得挺热的,那就是台电是不是要用回安卓系统了?你有没有想过,这个小小的决定背后...