线程同步—线程锁

news/2024/7/7 14:31:37

一、原子访问:Interlocked系列函数

可以保证一个值的操作是一个原子操作。实际的代码执行过程如下:

//C++代码:
g_x++;

//汇编:
MOV EAX, [g_x]
INC EAX
MOV [g_X], EAX

从上面的代码可以看出,即便是单条C++代码,编译为汇编后也会变成多条汇编指令。所以g_x++并非原子操作,也会出现多线程同步问题。
Interlocaked系列函数就是用来保障一次赋值操作是一个原子操作的。

LONG InterlockedExchangeAdd(
    PLONG volatile plAddend,
    LONG lIncrement
);
LONGLONG InterlockedExchangeAdd64(
    PLONGLONG volatile pllAddend,
    LONGLONG llIncrement
);
//使用方法:
long g_x = 0;
InterlockedExchangeAdd(&g_x, 1);

这样就可以保障g_x加上任意LONG数据都是一个原子操作。
这里需要注意的是,传给该函数的变量地址必须是经过对齐的,否则会失败。因为这个函数的原理是锁定一块内存区,这个内存区长度是sizeof(LONG)。如果地址是没有对齐的,那就会导致LONG数据是从两个内存块中读出来的,导致其中一块没有锁定,最终可能会出现同步失败的问题。

void* _aligned_malloc(size_t size, size_t alignment);

该函数可以申请一块对齐过的内存。其中的size表示长度,alignment表示对齐到的字节边界,传给alignment参数的值必须是2的整数幂次方。
InterlockedExchangeAdd也可以做减法,只需要传入一个负值即可。InterlockedExchangeAdd会返回*plAddend中原来的值。
下面还有一些相关的原子锁函数:

LONG InterlockedExchange(
    PLONG volatile plTarget,
    LONG lValue
);
LONGLONG InterlockedExchange64(
    PLONGLONG volatile plTarget,
    LONGLONG lValue
);
PVOID InterlockedExchangePointer(
    PVOID* volatile ppvTarget,
    PVOID pvValue
);

InterlockedExchange和InterlockedExchangePointer会把第一个参数所指向的内存地址的当前值,以原子方式替换为第二个参数指定的值。InterlockedExchangePointer函数在32位程序中替换的是32位值,64位程序中替换的是64位值。

BOOL g_fResourceInUse = FALSE;
InterlockedExchange(&g_fResourceInUse, TRUE);

Interlocked系列函数中还有一种特殊的单向链表栈。

InitializeSListHead          //创建一个空栈
InterlockedPushEntrySList    //在栈顶添加一个元素
InterlockedPopEntrySList     //移除位于栈顶的元素并将它返回
InterlockedFlushSList        //清空栈
QueryDepthSList              //返回栈中的元素的数量

上面的单向链表栈的操作全都是原子操作。

二、关键段

CRITICAL_SECTION g_cs;

VOID InitializeCriticalSection(PCRITICAL_SECTION pcs);
VOID DeleteCriticalSection(PCRITICAL_SECTION pcs);
VOID EnterCriticalSection(PCRITICAL_SECTION pcs);
BOOL TryEnterCriticalSection(PCRITICAL_SECTION pcs);
VOID LeaveCriticalSection(PCRITICAL_SECTION pcs);

LONG g_x = 0;
EnterCriticalSection(&g_cs);
g_x++;
LeaveCriticalSection(&g_cs);

TryEnterCriticalSection函数是不会阻塞的,他会通过返回值表明当前资源是否可以访问。如果当前资源正在被占用,则返回FALSE;如果返回的是TRUE,则需要调用LeaveCriticalSection。
由于EnterCriticalSection在等待时会将线程切换到等待状态。这意味着线程必须从用户模式切换到内核模式,这个开销很大。所以有一种新的接口方式来解决该问题:旋转锁+关键段。

//使用旋转锁初始化关键段
BOOL InitializeCriticalSectionAndSpinCount(
    PCRITICAL_SECTION pcs,
    DWORD dwSpinCount
);
//修改旋转锁循环次数
DWORD SetCriticalSectionSpinCount(
    PCRITICAL_SECTION pcs,
    DWORD dwSpinCount
);

旋转锁是一个类似死循环的锁,所以很占用CPU,但不需要进行内核切换。所以速度要比关键端快。InitializeCriticalSectionAndSpinCount函数第一个参数是一个关键段,第二个参数表示旋转锁的循环次数。范围是0-0x00FFFFFF。当循环结束时,资源如果还被占用着,就会自动从旋转锁切换到关键段。(用来保护进程堆的关键段所使用的旋转次数是4000,可以作为参考值)。

三、Slim读/写锁

SRWLock锁在读取资源时是不锁定的,只有在写资源时才会被锁定。

typedef struct _RTL_SRWLOCK{
    PVOID Ptr;
}RTL_SRWLOCK, *PRTL_SRWLOCK;

VOID InitializeSRWLock(PSRWLOCK SRWLock);
VOID ReleaseSRWLock(PSRWLOCK SRWLock);
//写锁
VOID AcquireSRWLockExclusive(PSRWLOCK SRWLock);
VOID ReleaseSRWLockExclusive(PSRWLOCK SRWLock);
//读锁
VOID AcquireSRWLockShared(PSRWLOCK SRWLock);
VOID ReleaseSRWLockShared(PSRWLOCK SRWLock);

http://www.niftyadmin.cn/n/2663399.html

相关文章

为什么Google比Yahoo!成功

先来看一下一项最新的搜索 市场调查结果(by Nielsen//NetRatings),如左图所示,搜索市场的前三名依然是Google、Yahoo!及MSN,它们的市场占有率(美国)分别是48.2%、22.2%、11%。耐人寻味的是&…

搞事情!英伟达最便宜 AI 新硬件,仅 99 美元

(给技术最前线加星标,每天看技术热点)原创整理:技术最前线(ID: TopITNews)参考:Engadget 和 Nvidia一般来说,复杂的人工智能不适合微型电脑一类的自制设备,因为微型电脑几乎不能处理基本功能之外…

微软更新太复杂 美夏令时间转换IT人员耗时大

微软更新太复杂 美夏令时间转换IT人员耗时大[more]4月29日国际报道 美国日光节约时间(夏令时间)调整中,企业发现准备过程既复杂又耗时,尤其对微软Windows电子邮件与服务器软件而言更是如此。依照新法规规定,今年美国的日光节约时间(daylight …

DHTML页面飞动与随机出现名人名言效果

<script language"javascript" type"text/javascript" src"http://www.feedsky.com/msub_ajax_sub_js.html?burlsoftwave&t1&corange"></script>代码在IE6,Firefox1.7,Opera9下运行了通过。<html xmlns"http://www…

Google招不到人?

要成为Google的员工一点也不容易。不相信&#xff1f;那请你试着回答这两道经常出现在Google面试中的问题先。问题一&#xff1a;用三句话向你的8岁的侄子解释什么是数据库&#xff1b;问题二&#xff1a;你认为在美国一共有多少个加油站&#xff1f;Google不久前在英国伦敦设立…

Windows—进程

一、概念 想要理解进程&#xff0c;首先要知道什么是进程。举一个简单的例子。当我们打开任务管理器时&#xff0c;会看到列表中有很多的条目&#xff0c;如下&#xff1a; 而这一行行的数据就是windows的进程。同时&#xff0c;我们可以发现这些进程都是以exe来命名的。事实…

李开复:不明白为何整天有人传我离职

李开复&#xff1a;不明白为何整天有人传我离职[more]4月27日&#xff0c;Google CEO埃里克施密特访华&#xff0c;其上次访华则是一年前为了“谷歌”成立的发布会。就在4月初&#xff0c;Google中国由于输入法抄袭的事件在全球媒体都引起了广泛讨论&#xff0c;此次来华&#…

Java 12 正式发布;Caffe 作者贾扬清官宣加盟阿里

(给技术最前线加星标&#xff0c;每天看技术热点)转自&#xff1a;开源中国、solidot、cnBeta、腾讯科技、快科技等【技术资讯】0、Java 12 / JDK 12 正式发布自 2 月 7 日开始&#xff0c;Java/JDK 12 就进入了 RC 阶段。按照发布周期&#xff0c;美国当地时间 3 月 19 日&…