自旋锁与互斥锁的对比、手工实现自旋锁

互斥锁 vs 自旋锁:底层机制详细解析 本文详细解析互斥锁与自旋锁的底层机制,帮助你掌握高效并发编程的核心技术。 阅读详情

    本文地址:(LYanger的博客:http://blog.youkuaiyun.com/freeelinux/article/details/53695111)


    本文之前,我只是对自旋锁有所了解,知道它是做什么的,但是没有去测试实现过,甚至以为自旋锁只有kernel用这个,今天才发现POSIX有提供自旋锁的接口。下面我会分析一下自旋锁,并代码实现自旋锁和互斥锁的性能对比,以及利用C++11实现自旋锁。


一:自旋锁(spin lock)

    自旋锁是一种用于保护多线程共享资源的锁,与一般互斥锁(mutex)不同之处在于当自旋锁尝试获取锁时以忙等待(busy waiting)的形式不断地循环检查锁是否可用。
在多CPU的环境中, 对持有锁较短的程序来说,使用自旋锁代替一般的互斥锁往往能够提高程序的性能。

    最后标红的句子很重要,本文将针对该结论进行验证。

    下面是man手册中对自旋锁pthread_spin_lock()函数的描述:

DESCRIPTION
       The  pthread_spin_lock() function shall lock the spin lock referenced by lock. The calling thread shall acquire the lock if
       it is not held by another thread. Otherwise, the thread shall spin (that is, shall not return from the  pthread_spin_lock()
       call)  until  the  lock  becomes available.  The results are undefined if the calling thread holds the lock at the time the
       call is made. The pthread_spin_trylock() function shall lock the spin lock referenced by lock if it  is  not  held  by  any
       thread. Otherwise, the function shall fail.

       The results are undefined if any of these functions is called with an uninitialized spin lock.

    可以看出,自选锁的主要特征:当自旋锁被一个线程获得时,它不能被其它线程获得。如果其他线程尝试去phtread_spin_lock()获得该锁,那么它将不会从该函数返回,而是一直自旋(spin),直到自旋锁可用为止。

    使用自旋锁时要注意:
  • 由于自旋时不释放CPU,因而持有自旋锁的线程应该尽快释放自旋锁,否则等待该自旋锁的线程会一直在哪里自旋,这就会浪费CPU时间。
  • 持有自旋锁的线程在sleep之前应该释放自旋锁以便其他咸亨可以获得该自旋锁。内核编程中,如果持有自旋锁的代码sleep了就可能导致整个系统挂起。(下面会解释)
    使用任何锁都需要消耗系统资源(内存资源和CPU时间),这种资源消耗可以分为两类:
        1.建立锁所需要的资源
        2.当线程被阻塞时所需要的资源

POSIX提供的与自旋锁相关的函数有以下几个,都在<pthread.h>中。

int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
初始化spin lock, 当线程使用该函数初始化一个未初始化或者被destroy过的spin lock有效。该函数会为spin lock申请资源并且初始化spin lock为unlocked状态。
有关第二个选项是这么说的:
       If  the  Thread  Process-Shared Synchronization option is supported and the value of pshared is PTHREAD_PROCESS_SHARED, the
       implementation shall permit the spin lock to be operated upon by any thread that has access to the memory  where  the  spin
       lock is allocated, even if it is allocated in memory that is shared by multiple processes.

       If the Thread Process-Shared Synchronization option is supported and the value of pshared is PTHREAD_PROCESS_PRIVATE, or if
       the option is not supported
, the spin lock shall only be operated upon by threads created within the same  process  as  the
       thread that initialized the spin lock. If threads of differing processes attempt to operate on such a spin lock, the behav‐
       ior is undefined.

所以,如果初始化spin lock的线程设置第二个参数为PTHREAD_PROCESS_SHARED,那么该spin lock不仅被初始化线程所在的进程中所有线程看到,而且可以被其他进程中的线程看到,PTHREAD_PROESS_PRIVATE则只被同一进程中线程看到。如果不设置该参数,默认为后者。

 int pthread_spin_destroy(pthread_spinlock_t *lock);
销毁spin lock,作用和mutex的相关函数类似,就不翻译了:
 The  pthread_spin_destroy()  function  shall destroy the spin lock referenced by lock and release any resources used by the
       lock. The effect of subsequent use of  the  lock  is  undefined  until  the  lock  is  reinitialized  by  another  call  to
       pthread_spin_init(). The results are undefined if pthread_spin_destroy() is called when a thread holds the lock, or if this
       function is called with an uninitialized thread spin lock.
不过和mutex的destroy函数一样有这样的性质(当初害惨了我):
The result of referring to copies of that object in calls to pthread_spin_destroy(), pthread_spin_lock(), pthread_spin_try‐
       lock(), or pthread_spin_unlock() is undefined.

int pthread_spin_lock(pthread_spinlock_t *lock);
加锁函数,功能上文都说过了,不过这么一点值得注意:
EBUSY  A thread currently holds the lock.
       These functions shall not return an error code of [EINTR].

int pthread_spin_trylock(pthread_spinlock_t *lock);
还有这个函数,这个一般很少用到。

int pthread_spin_unlock(pthread_spinlock_t *lock);
解锁函数。不是持有锁的线程调用或者解锁一个没有lock的spin lock这样的行为都是undefined的。


二:自旋锁和互斥锁的区别

    以下该段内容引自 http://blog.chinaunix.net/uid-28711483-id-4995776.html:
    
    从实现原理上来讲,Mutex属于sleep-waiting类型的 锁。例如在一个双核的机器上有两个线程(线程A和线程B),它们分别运行在Core0和Core1上。假设线程A想要通过 pthread_mutex_lock操作去得到一个临界区的锁,而此时这个锁正被线程B所持有,那么线程A就会被阻塞(blocking),Core0 会在此时进行上下文切换(Context Switch)将线程A置于等待队列中, 此时Core0就可以运行其他的任务(例如另一个线程C)而不必进行忙等待。而Spin lock则不然,它属于busy-waiting类型的锁,如果线程A是使用pthread_spin_lock操作去请求锁,那么线程A就会一直在 Core0上进行忙等待并不停的进行锁请求,直到得到这个锁为止。
       如果大家去查阅Linux glibc中对pthreads API的实现NPTL(Native POSIX Thread Library) 的源码的话(使用”getconf GNU_LIBPTHREAD_VERSION”命令可以得到我们系统中NPTL的版本号),就会发现pthread_mutex_lock()操作如果 没有锁成功的话就会调用system_wait()的系统调用并将当前线程加入该mutex的等待队列里。而spin lock则可以理解为在一个while(1)循环中用内嵌的汇编代码实现的锁操作(印象中看过一篇论文介绍说在linux内核中spin lock操作只需要两条CPU指令,解锁操作只用一条指令就可以完成)。有兴趣的朋友可以参考另一个名为sanos的微内核中pthreds API的实现:mutex.c spinlock.c,尽管与NPTL中的代码实现不尽相同,但是因为它的实现非常简单易懂,对我们理解spin lock和mutex的特性还是很有帮助的。
        对于自旋锁来说,它只需要消耗很少的资源来建立锁;随后当线程被阻塞时,它就会一直重复检查看锁是否可用了,也就是说当自旋锁处于等待状态时它会一直消耗CPU时间。
        对于互斥锁来说,与自旋锁相比它需要消耗大量的系统资源来建立锁;随后当线程被阻塞时,线程的调度状态被修改,并且线程被加入等待线程队列;最后当锁可用 时,在获取锁之前,线程会被从等待队列取出并更改其调度状态;但是在线程被阻塞期间,它不消耗CPU资源。
        因此自旋锁和互斥锁适用于不同的场景。自旋锁适用于那些仅需要阻塞很短时间的场景,而互斥锁适用于那些可能会阻塞很长时间的场景。


四:自旋锁与linux内核进程调度关系


    现在我们就来说一说之前的问题,如果临界区可能包含引起睡眠的代码则不能使用自旋锁,否则可能引起死锁:
    那么为什么信号量保护的代码可以睡眠而自旋锁会死锁呢?

    先看下自旋锁的实现方法吧,自旋锁的基本形式如下:
    spin_lock(&mr_lock):
    
    //critical region

    spin_unlock(&mr_lock);
    跟踪一下spin_lock(&mr_lock)的实现

    #define spin_lock(lock) _spin_lock(lock)
    #define _spin_lock(lock) __LOCK(lock)
    #define __LOCK(lock) \
    do { preempt_disable(); __acquire(lock); (void)(lock); } while (0)
    
    注意到“preempt_disable()”,这个调用的功能是“关抢占”(在spin_unlock中会重新开启抢占功能)。从中可以看出,使用自旋锁保护的区域是工作在非抢占的状态;即使获取不到锁,在“自旋”状态也是禁止抢占的。了解到这,我想咱们应该能够理解为何自旋锁保护 的代码不能睡眠了。试想一下,如果在自旋锁保护的代码中间睡眠,此时发生进程调度,则可能另外一个进程会再次调用spinlock保护的这段代码。而我们 现在知道了即使在获取不到锁的“自旋”状态,也是禁止抢占的,而“自旋”又是动态的,不会再睡眠了,也就是说在这个处理器上不会再有进程调度发生了,那么 死锁自然就发生了。

    总结下自旋锁的特点:
  • 单CPU非抢占内核下:自旋锁会在编译时被忽略(因为单CPU且非抢占模式情况下,不可能发生进程切换,时钟只有一个进程处于临界区(自旋锁实际没什么用了)
  • 单CPU抢占内核下:自选锁仅仅当作一个设置抢占的开关(因为单CPU不可能有并发访问临界区的情况,禁止抢占就可以保证临街区唯一被拥有)
  • 多CPU下:此时才能完全发挥自旋锁的作用,自旋锁在内核中主要用来防止多处理器中并发访问临界区,防止内核抢占造成的竞争。


五:linux发生抢占的时间

    linux抢占发生的时间,抢占分为 用户抢占和 内核抢占。

    用户抢占在以下情况下产生:
  • 从系统调用返回用户空间
  • 从中断处理程序返回用户空间
    内核抢占会发生在:
  • 当从中断处理程序返回内核空间的时候,且当时内核具有可抢占性
  • 当内核代码再一次具有可抢占性的时候(如:spin_unlock时)
  • 如果内核中的任务显示的调用schedule()      (这个我暂时不太懂)
    基本的进程调度就是发生在时钟中断后,并且发现进程的时间片已经使用完了,则发生进程抢占。通常我们会利用中断处理程序返回内核空间的时候可进行内核抢占这个特性来提高一些I/O操作的实时性,如:当I/O事件发生的时候,对应的中断处理程序被激活,当它发现有进程在等待这个I/O事件的时候,它 会激活等待进程,并且设置当前正在执行进程的need_resched标志,这样在中断处理程序返回的时候,调度程序被激活,原来在等待I/O事件的进程 (很可能)获得执行权,从而保证了对I/O事件的相对快速响应(毫秒级)。可以看出,在I/O事件发生的时候,I/O事件的处理进程会抢占当前进程,系统 的响应速度与调度时间片的长度无关。

六:spin_lock和mutex实际效率对比

1.++i是否需要加锁?

    我分别使用POSIX的spin_lock和mutex写了两个累加的程序,启动了两个线程,并利用时间戳计算它们执行完累加所用的时间。

    下面这个是使用spin_lock的代码,我启动两个线程同时对num进行++,使用spin_lock保护临界区,实际上可能会有疑问++i(++i和++num本文中是一个意思)为什么还要加锁?
     i++需要加锁是很明显的事情,对i++的操作的印象是,它一般是三步曲,从内存中取出i放入寄存器中,在寄存器中对i执行inc操作,然后把i放回内存中。这三步明显是可打断的,所以需要加锁。
    但是++i可能就有点犹豫了。实际上印象流是不行的,来看一下i++和++i的汇编代码,其实他们是一样的,都是三步,我只上一个图就行了,如下:

    所以++i也不是原子操作,在多核的机器上,多个线程在读取内存中的i时,可能读取到同一个值,这就导致多个线程同时执行+1,但实际上它们得到的结果是一样的,即i只加了一次。还有一点:这几句汇编正说明了++i和i++i对于效率是一样的,不过这只是针对内建POD类型而言,如果是class的话,我们都写过类的++运算符的重载,如果一个类在单个语句中不写++i,而是写i++的话,那无疑效率会有很大的损耗。(有点跑题)

2.spin_lock代码

首先是spin_lock实现两个线程同时加一个数,每个线程均++num,然后计算花费的时间。
#include <iostream>
#include <thread>

#include <pthread.h>
#include <sys/time.h>
#include <unistd.h>

int num = 0;
pthread_spinlock_t spin_lock;

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<100000000; ++i){
        pthread_spin_lock(&spin_lock);
        ++num;
        pthread_spin_unlock(&spin_lock);
    }   
}

int main()
{
    pthread_spin_init(&spin_lock, PTHREAD_PROCESS_PRIVATE);//maybe PHREAD_PROCESS_PRIVATE or PTHREAD_PROCESS_SHARED

    int64_t start = get_current_timestamp();

    std::thread t1(thread_proc), t2(thread_proc);
    t1.join();
    t2.join();

    std::cout<<"num:"<<num<<std::endl;
    int64_t end = get_current_timestamp();
    std::cout<<"cost:"<<end-start<<std::endl;

    pthread_spin_destroy(&spin_lock);

    return 0;
}

3.mutex代码

#include <iostream>
#include <thread>

#include <pthread.h>
#include <sys/time.h>
#include <unistd.h>

int num = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

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()
{
    int64_t start = get_current_timestamp();
   std::thread t1(thread_proc), t2(thread_proc);
    t1.join();
    t2.join();
    std::cout<<"num:"<<num<<std::endl;
    int64_t end = get_current_timestamp();
    std::cout<<"cost:"<<end-start<<std::endl;

    pthread_mutex_destroy(&mutex);    //maybe you always foget this

    return 0;
}

4.结果分析

得出的结果如图,num是最终结果,cost是花费时间,单位为us,main2是使用spin lock,


    显然,在临界区只有++num这一条语句的情况下,spin lock相对花费的时间短一些,实际上它们有可能接近的情况,取决于CPU的调度情况,但始终会是spin lock执行的效率在本情况中花费时间更少。

    我修改了两个程序中临界区的代码,改为:
   for(int i=0; i<1000000; ++i){
        pthread_spin_lock(&spin_lock);
        ++num;
        for(int i=0; i<100; ++i){
            //do nothing
        }   
        pthread_spin_unlock(&spin_lock);
    }   
    另一个使用mutex的程序也加了这么一段,然后结果就与之前的情况大相径庭了:

    实验结果是如此的明显,仅仅是在临界区内加了一个10圈的循环,spin lock就需要花费比mutex更长的时间了。
    
    所以, spin lock虽然lock/unlock的性能更好(花费很少的CPU指令),但是它只适应于临界区运行时间很短的场景。实际开发中,程序员如果对自己程序的锁行为不是很了解,否则使用spin lock不是一个好主意。更保险的方法是使用mutex,如果对性能有进一步的要求,那么再考虑spin lock。

七:使用C++实现自主实现自旋锁

由于前面原理已经很清楚了,现在直接给代码如下:
#pragma once

#include <atomic>

class spin_lock {
private:
    std::atomic<bool> flag = ATOMIC_VAR_INIT(false);
public:
    spin_lock() = default;
    spin_lock(const spin_lock&) = delete;
    spin_lock& operator=(const spin_lock) = delete;
    void lock(){   //acquire spin lock
        bool expected = false;
        while(!flag.compare_exchange_strong(expected, true));
            expected = false;    
    }   
    void unlock(){   //release spin lock
        flag.store(false);
    }   
};
测试文件,仅给出关键部分:
int num = 0;
spin_lock sm; 

void thread_proc()
{
    for(int i=0; i<10000000; ++i){
        sm.lock();
        ++num;
        sm.unlock();
    }   
}



好的,对自旋锁的总结就先到这里了。





【操作系统】自旋锁和互斥锁 通过合理选择锁机制,可以在并发性能和资源利用率之间取得最佳平衡。自旋锁和互斥锁是用于多线程同步的两种常见锁机制,主要区别在于。根据实际场景选择锁机制,是高性能并发程序设计的核心技能之一。 阅读详情

相关推荐

别再死记硬背了!用C语言手写一个test_and_set(),彻底搞懂硬件锁的原理

本文通过C语言手写`test_and_set()`函数,深入解析硬件锁的原子性原理,帮助读者彻底理解操作系统中的硬件同步机制。从非原子实现到模拟原子操作,再到构建完整的互斥锁演示系统,逐步揭示临界区保护和互斥实现的底层奥秘,适合对操作系统和并发编程感兴趣的开发者学习。

weixin_30781433的博客 317

自旋锁和互斥锁的区别

序言 最底层的两种锁实现就是互斥锁和自旋锁,许多高级的锁都是基于他们实现的。 加锁的目的是保证共享资源在任意时间内,只有一个线程访问,这样就可以避免多线程导致共享数据错乱的问题。 当有一个线程加锁成功后,其他线程就会加锁失败。 1、互斥锁 互斥锁是一种独占锁,当线程A加锁成功后,此时互斥锁已经被线程A独占了,只要线程A没有释放手中的锁,线程B就会失败,就会释放掉CPU给其他线程,线程B加锁的代码就会被阻塞。 互斥锁加锁失败而阻塞是由操作系统内核实现的,当加锁失败后,内核将线程置为睡眠状态,等

Yisnow.的博客 1万+

保姆级教程:在阿里云ECS上用Docker一键部署EMQX MQTT服务器(Ubuntu 20.04)

本文提供在阿里云ECS上使用Docker一键部署EMQX MQTT服务器的详细教程,涵盖从实例创建、Docker环境配置到EMQX部署与优化的全流程。适合物联网开发者快速搭建高效、安全的MQTT消息服务器,适用于智能家居、工业物联网等场景。

weixin_28739079的博客 308

自旋锁与互斥锁区别

自旋锁(Spinlock):当线程尝试获取一个已被占用的自旋锁时,它不会立即放弃CPU,而是原地循环(自旋),不断检查锁的状态,直到锁变为可用。因此,自旋锁在获取锁的开销较小,尤其是在锁很快就能被释放的场景下。互斥锁(Mutex):当一个线程试图锁定一个已经被其他线程持有的互斥锁时,该线程会被操作系统挂起(进入睡眠状态),并从运行队列移除,直到锁被释放,操作系统才会唤醒该线程,将其放回运行队列。互斥锁虽然在获取锁失败时会引入较高的上下文切换开销,但在锁等待时间较长时,可以让出CPU资源,避免资源浪费。

u012772347的博客 1422

MDB协议中设备级别和选项(Levels and Options)

MDB协议的LEVEL级别介绍

hbstart的博客 936

【计算机图形学】Pov-Ray画的垃圾小车

效果: 代码: #include "colors.inc" #include "metals.inc" #include "glass.inc" //相机 //这个位置车子刚好落在草地上了 camera { location direction z*1.5 right x*image_width/image_height look_at

lishichengyan的博客 1749

【自旋锁】用“忙等待“换“低延迟“——自旋锁原理与实战

本文将从自旋锁的底层原理出发,用原子操作手写一个自旋锁,再深入 Linux 的 pthread_spinlock 系统调用,最后通过售票系统的实战案例对比互斥锁和自旋锁的性能差异。读完本文,你将能够:独立解释自旋锁和互斥锁在"等待机制"上的本质区别,在合适的场景下用 pthread_spinlock 替代 mutex 以获得更低延迟,并清楚地判断什么样的临界区适合自旋锁、什么样的绝对不能用。

2302_80243065的博客 1188

Python爬虫实战:5分钟搞定微信公众号文章阅读数、点赞数抓取(附完整代码)

本文详细介绍了如何通过Python爬虫技术自动化抓取微信公众号文章的阅读数和点赞数。文章从数据源分析入手,分步讲解了获取文章列表与提取单篇统计数据的完整流程,并提供了应对平台风控的策略与工程化整合方案,帮助开发者高效、合规地完成数据采集任务。

ansible6ops的博客 1332

java编程思想和java核心

什么是自旋锁和互斥锁? 由于CLH锁是一种自旋锁,那么我们先来看看自旋锁是什么? 自旋锁说白了也是一种互斥锁,只不过没有抢到锁的线程会一直自旋等待锁的释放,处于busy-waiting的状态,此时等待锁的线程不会进入休眠状态,而是一直忙等待浪费CPU周期。因此自旋锁适用于锁占用时间短的场合。 这里谈到了自旋锁,那么我们也顺便说下互斥锁。这里的互斥锁说的是传统意义的互斥锁,就是多个线程并发竞争锁的时候,没有抢到锁的线程会进入休眠状态即sleep-waiting,当锁被释放的时候,处于休眠状态的一个线程会再次获

m0_57541165的博客 138

从手机到单片机:聊聊ARM Cortex家族那些事,A、R、M系列到底有啥不同?

本文深入解析ARM Cortex家族的A、R、M三大系列处理器,揭示它们在性能、实时响应和能效方面的核心差异。从智能手机到汽车电子和物联网设备,Cortex-A、R、M各司其职,分别应对复杂运算、实时控制和超低功耗场景。通过技术指标对比和典型应用案例,帮助开发者理解如何根据DMIPS/MHz等关键参数选择适合的处理器架构。

weixin_31574149的博客 350

RandLA-Net Tensorrt 推理 c++

RandLA-Net 实现 Tensorrt 部署.

J。 1108

Atitit.软件与编程语言中的锁机制原理attilax总结

Atitit.软件与编程语言中的锁机制原理attilax总结   1. 用途 (Db,业务数据加锁,并发操作加锁。1 2. 锁得类型 排它锁 “互斥锁 共享锁 乐观锁与悲观锁1 2.1. 自旋锁还是信号量1 2.2. -自动释放还是手动释放1 3. 实现方式,语言方式与库方式1 4. Java的锁机制 Synchronized ReentrantLock Atomi

attilax的专栏 571

基于simulink的多能源系统协同控制的复杂场景实例:氢燃料电池+锂电池混合动力电动汽车能量管理仿真

本文介绍了基于Simulink的氢燃料电池与锂电池混合动力电动汽车能量管理系统的建模与仿真方法。系统包含驾驶循环输入、氢燃料电池、锂电池、能量管理和电机驱动等模块,通过Simulink实现各模块的协同控制。文章详细说明了从模型创建到性能评估的完整流程,包括驾驶循环输入设置、燃料电池和锂电池子系统建模、能量管理策略设计等关键步骤。该仿真模型可验证不同工况下的系统响应和能量利用效率,为优化混合动力汽车的能量管理策略提供有效工具。通过引入更复杂的物理细节和环境因素,可进一步提升模型的实用性和准确性。

xiaoheshang_123的博客 368

字符设备驱动第八课---运用程序与驱动程序同步与互斥机制的对比

运用程序与驱动程序在同步互斥方面的一些相同点与不同点

u010243305的博客 451

csp信奥赛C++标准模板库STL案例应用1

csp信奥赛C++标准模板库STL案例应用1

王老师青少年编程 1381

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

常见嵌入式操作系统中的并发与竞争保护机制

本文系统性的梳理了嵌入式并发保护的十大机制:关中断、关调度、自旋锁、互斥锁、信号量、读写锁、原子操作、无锁结构、临界区抽象与内存屏障。每种机制先讲原理与适用边界,再逐一给出 Linux、FreeRTOS、μC/OS-II/III、RT-Thread、Zephyr、ThreadX、NuttX、LiteOS、AliOS Things 共 10 个系统的接口详解与实现差异,并对优先级反转、选型决策给出对照表、思维导图与工程军规,可作为跨平台开发与技术选型的速查手册。

smallerxuan的博客 6971

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Synchronized与ReentrantLock区别总结

这篇文章是关于这两个同步锁的简单总结比较,关于底层源码实现原理没有过多涉及,后面会有关于这两个同步锁的底层原理篇幅去介绍。 相似点: 这两种同步方式有很多相似之处,它们都是加锁方式同步,而且都是阻塞式的同步,也就是说当如果一个线程获得了对象锁,进入了同步块,其他访问该同步块的线程都必须阻塞在同步块外面等待,而进行线程阻塞和唤醒的代价是比较高的(操作系统需要在用户态与内核态之间来回切换,代价很高,...

zhibinLi的博客 272

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Linux Mutex 工作原理与实现机制深度剖析

机制作用优势快速路径无竞争时快速获取极低开销, 单原子操作乐观自旋多核环境下自旋等待减少上下文切换开销等待队列管理等待线程保证公平性, 避免饥饿Handoff机制直接传递锁所有权减少唤醒开销, 提高公平性。

X 576

Synchronized与ReentrantLock 有啥区别

Synchronized与ReentrantLock 有啥区别 相似点: 这两种同步方式有很多相似之处,它们都是加锁方式同步,而且都是阻塞式的同步,也就是说当如果一个线程获得了对象锁,进入了同步块,其他访问该同步块的线程都必须阻塞在同步块外面等待,而进行线程阻塞和唤醒的代价是比较高的(操作系统需要在用户态与内核态之间来回切换,代价很高,不过可以通过对锁优化进行改善)。 不同点: ...

FireAny2010的专栏 323

MIT 6.S081 Lab 7:xv6内核多线程与同步原语实现详解

并发编程是现代计算机系统的核心基础,它允许多个执行流同时运行以提升资源利用率和程序性能。其基本原理是通过线程或进程共享CPU时间片或利用多核处理器实现并行。在操作系统层面,这带来了数据竞争、死锁等关键挑战,需要通过同步原语来管理共享资源的访问。锁、条件变量和屏障等技术为解决这些问题提供了工程实践方案,广泛应用于数据库、Web服务器和高性能计算等场景。本文以MIT 6.S081操作系统课程的Lab 7实验为具体案例,深入探讨如何在xv6教学内核中实现用户级线程和内核同步机制。通过剖析线程控制块、上下文切换和自

weixin_34310369的博客 994

synchronized与ReenTrantLock详解

synchronized与ReenTrantLock详解相似点:功能区别:底层实现区别便利性区别细粒度和灵活度区别性能的区别:SynchronizedReentrantLock公平锁、非公平锁的创建方式:ReenTrantLock实现的原理: 相似点: 这两种同步方式有很多相似之处,它们都是加锁方式同步,而且都是阻塞式的同步,也就是说当如果一个线程获得了对象锁,进入了同步块,其他访问该同步块的线程...

qq_34316768的博客 369

【面经专栏】自己整理的操作系统面经

1、需要线程频繁加锁解锁的场景,怎么优化CPU性能 临界区处理很快,也许用 spin lock(自旋锁) 或者 lock-free 算法,临界区处理很慢, mutex 更合适 lock-free:是一种编程思想,指的是使用多线程的条件下,尽量少使用锁以降低线程之间互相阻塞的机会;在一系列访问 Lock-Free 操作的线程中,如果某一个线程被挂起,那么其绝对不会阻止其他线程继续运行 不要使用自旋锁,因为线程得不到锁的时候会一直在循环等待,不会进入休眠 使用互斥锁,结合条件变量,引入线程的等待与通知机

日月既往,不可复追 2408
上一篇: 完全二叉树统计节点个数【使用二分搜索】
下一篇: GDB常用调试命令以及多进程多线程调试
FreeeLinux
博客等级 码龄11年 421粉丝 356原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值