• 关键代码段(Critical Sections) 和自旋锁(Spinlocks)


    写在前面:今天一哥们问我,windows的临界代码是自旋还是等待,当时想了想应该是等待,后来翻了一下《Windows via C/C++》,发现还有点小意思。总结一下先。

    关键代码段是指一个小代码段,在代码能够执行前,它必须独占对某些共享资源的访问权。这是让若干行代码能够“以原子操作方式”来使用资源的一种方法。所谓原子操作方式,是指该代码知道没有别的线程要访问该资源。当然,系统仍然能够抑制你的线程的运行,而抢先安排其他线程的运行。不过,在线程退出关键代码段之前,系统将不给想要访问相同资源的其他任何线程进行调度。
    来看一段使用关键代码段的程序:
    const int COUNT = 10;
    int g_nSum = 0;
    CRITICAL_SECTION g_cs;

    DWORD WINAPI FirstThread(PVOID pvParam) {
       EnterCriticalSection(
    &g_cs);
       g_nSum 
    = 0;
       
    for (int n = 1; n <= COUNT; n++) {
          g_nSum 
    += n;
       }
       LeaveCriticalSection(
    &g_cs);
       
    return(g_nSum);
    }


    DWORD WINAPI SecondThread(PVOID pvParam) {
       EnterCriticalSection(
    &g_cs);
       g_nSum 
    = 0;
       
    for (int n = 1; n <= COUNT; n++) {
          g_nSum 
    += n;
       }
       LeaveCriticalSection(
    &g_cs);
       
    return(g_nSum);
    }

    当一个线程进入关键代码段,其它请求进入关键代码段的线程就会进入等待状态,这意味着该线程必须从用户方式转入内核方式(大约1000个C P U周期),这种转换是要付出很大代价的。 而对于多CPU系统,有时候这是没有必要的,实际上拥有资源的线程可以在另一个线程完成转入内核方式之前释放资源。
    所以,为了提高性能,Microsoft将自旋锁引入关键代码段。当EnterCriticalSection函数被调用时,如果关键代码段已经被其它线程持有时,它就原地自旋,当自旋一定次数后还不能获取关键代码段,此时线程才转入内核方式,进入等待状态。

    若要将自旋锁用于关键代码段,应该调用下面的函数,以便对关键代码段进行初始化:
    BOOL InitializeCriticalSectionAndSpinCount(
       PCRITICAL_SECTION pcs, DWORD dwSpinCount);
    其中,第二个参数dwSpinCount,传递的是在使线程等待之前它试图获得资源时自旋的次数。
    Linux的pthread对于线程提供了三种机制,互斥量(mutex)(功能大概相当于Windows的关键代码段),同时为了提高并发性,还引入了读写锁,此外,还提供了条件变量(相应的介绍见《Unix环境高级编程》)。
    由于windows的关键代码段工作在用户态, 所以开销应该要小于Linux互斥量。不知道为什么,pthread没有提供自旋锁机制,仅管内核大量的使用自旋锁。
  • 相关阅读:
    高德地图js开发,给城市某个区添加颜色
    threejs 实现易拉罐换肤功能
    React 跨页面保留前一页状态的一种实现方法
    nginx 解决客户端跟服务跨域问题
    React图片预览组件,支持缩放、旋转、上一张下一张功能
    h5 高德地图开发 谷歌浏览器定位失败解决方案
    echarts点击省份显示对应的省份
    sec:authorize 标签 通过不通过权限例子
    择左边多选框的值移动到右边多选框
    更改css element.style
  • 原文地址:https://www.cnblogs.com/hustcat/p/1576535.html
Copyright © 2020-2023  润新知