`

《Windows核心编程》---Interlocked原子访问系列函数

 
阅读更多

所谓原子访问,指的是一个线程在访问某个资源的同时能够保证没有其他线程会在同一时刻访问同一资源。Interlocked系列函数提供了这样的操作。所有这些函数会以原子方式来操控一个值。

Interlocked函数的工作原理取决于代码运行的CPU平台,如果是x86系列CPU,那么Interlocked函数会在总线上维持一个硬件信号,这个信号会阻止其他CPU访问同一个内存地址。我们必须确保传给这些函数的变量地址是经过对齐的,否则这些函数可能会失败。C运行库提供了一个_aligned_malloc函数,我们可以使用这个函数来分配一块对齐过的内存:

void * _aligned_malloc(

size_t size, //要分配的字节数

size_t alignment //要对齐到的字节边界,传给alignment的值必须是2的整数幂次方

);

Interlocked函数的另一个需要注意的点是它们执行得很快。调用一次Interlocked函数通常只占用几个CPU周期(通常小于50),而且不需要在用户模式和内核模式之间进行切换(这个切换通常需要占用1000CPU周期以上)。

1)原子加减操作InterlockedExchangeAdd函数原型如下:

LONG __cdecl InterlockedExchangeAdd( //32位值进行操作

__inout LONG volatile *Addend, //需要递增的变量地址

__in LONG Value //增量值,可为负值表示减法

);

LONGLONG __cdecl InterlockedExchangeAdd64( //64位值进行操作

__inout LONGLONG volatile *Addend,

__in LONGLONG Value

);

2InterlockedExchange函数用于原子地将32位整数设为指定的值:

LONG __cdecl InterlockedExchange(

__inout LONG volatile *Target, //指向要替换的32位值的指针

__in LONG Value //替换的值

);

返回值是指向原先的32位整数值。

InterlockedExchangePointer函数原子地用于替换地址值:

PVOID __cdecl InterlockedExchangePointer(

__inout PVOID volatile *Target, //指向要替换的地址值的指针

__in PVOID Value //替换的地址值

);

返回值是原来的地址值。

32位应用程序来说,以上两个函数都用一个32位值替换另一个32位值,但对64位应用程序来说,InterlockedExchange替换的是32位值,而InterlockedExchangePointer替换的是64位值。

当然,还有一个函数InterlockedExchange64专门用来原子地操作64位值的:

LONGLONG __cdecl InterlockedExchange64(

__inout LONGLONG volatile *Target,

__in LONGLONG Value

);

在实现旋转锁时,InterlockedExchange函数极其有用:

//标识一个共享资源是否正在被使用的全局变量

BOOL g_fResourceInUse = FALSE;

...

void ASCEFunc()

{

//等待访问共享资源

while(InterlockedExchange(&g_fResourceInUse, TRUE) == TRUE)

sleep(0);

//访问共享资源

...

//结束访问

InterlockedExchange(&g_fResourceInUse, FALSE);

}

注意,在使用这项技术时要小心,因为旋转锁会耗费CPU时间。特别是在单CPU机器上应该避免使用旋转锁,如果一个线程不停地循环,那么这会浪费宝贵的CPU时间,而且会阻止其他线程改变该锁的值。

3)函数InterlockedCompareExchange函数和InterlockedCompareExchangePointer函数原型如下:

LONG __cdecl InterlockedCompareExchange(

__inout LONG volatile *Destination, //当前值

__in LONG Exchange, //

__in LONG Comparand //比较值

);

PVOID __cdecl InterlockedCompareExchangePointer(

__inout PVOID volatile *Destination,

__in PVOID Exchange,

__in PVOID Comparand

);

这两个函数以原子方式执行一个测试和设置操作。对32位应用程序来说,这两个函数都对32位值进行操作;在64位应用程序中,InterlockedCompareExchange32位值进行操作而InterlockedCompareExchangePointer64位值进行操作。函数会将当前值(Destination指向的)与参数Comparand进行比较,如果两个值相同,那么函数会将*Destination修改为Exchange参数指定的值。若不等,则*Destination保持不变。函数会返回*Destination原来的值。所有这些操作都是一个原子执行单元来完成的。

当然,这两个函数的64位版本是:

LONGLONG __cdecl InterlockedCompareExchange64(

__inout LONGLONG volatile *Destination,

__in LONGLONG Exchange,

__in LONGLONG Comparand

);

4Interlocked单向链表函数

InitializeSListHead函数用于创建一个空的单向链表栈:

void WINAPI InitializeSListHead(

__inout PSLIST_HEADER ListHead

);

InterlockedPushEntrySList函数在栈顶添加一个元素:

PSLIST_ENTRY WINAPI InterlockedPushEntrySList(

__inout PSLIST_HEADER ListHead,

__inout PSLIST_ENTRY ListEntry

);

InterlockedPopEntrySList函数移除位于栈顶的元素并将其返回:

PSLIST_ENTRY WINAPI InterlockedPopEntrySList(

__inout PSLIST_HEADER ListHead

);

InterlockedFlushSList函数用于清空单向链表栈:

PSLIST_ENTRY WINAPI InterlockedFlushSList(

__inout PSLIST_HEADER ListHead

);

QueryDepthSList函数用于返回栈中元素的数量:

USHORT WINAPI QueryDepthSList(

__in PSLIST_HEADER ListHead

);

单向链表栈中元素的结构是:

typedef struct _SLIST_ENTRY {

struct _SLIST_ENTRY *Next;

} SLIST_ENTRY, *PSLIST_ENTRY;

注意:所有单向链表栈中的元素必须以MEMORY_ALLOCATION_ALIGNMENT方式对齐,使用_aligned_malloc函数即可。

实例如下:

#include <windows.h>

#include <malloc.h>

#include <stdio.h>

// Structure to be used for a list item; the first member is the

// SLIST_ENTRY structure, and additional members are used for data.

// Here, the data is simply a signature for testing purposes.

typedef struct _PROGRAM_ITEM {

SLIST_ENTRY ItemEntry;

ULONG Signature;

} PROGRAM_ITEM, *PPROGRAM_ITEM;

int main( )

{

ULONG Count;

PSLIST_ENTRY pFirstEntry, pListEntry;

PSLIST_HEADER pListHead;

PPROGRAM_ITEM pProgramItem;

// Initialize the list header to a MEMORY_ALLOCATION_ALIGNMENT boundary.

pListHead = (PSLIST_HEADER)_aligned_malloc(sizeof(SLIST_HEADER),

MEMORY_ALLOCATION_ALIGNMENT);

if( NULL == pListHead )

{

printf("Memory allocation failed./n");

return -1;

}

InitializeSListHead(pListHead);

// Insert 10 items into the list.

for( Count = 1; Count <= 10; Count += 1 )

{

pProgramItem = (PPROGRAM_ITEM)_aligned_malloc(sizeof(PROGRAM_ITEM),

MEMORY_ALLOCATION_ALIGNMENT);

if( NULL == pProgramItem )

{

printf("Memory allocation failed./n");

return -1;

}

pProgramItem->Signature = Count;

pFirstEntry = InterlockedPushEntrySList(pListHead,

&(pProgramItem->ItemEntry));

}

// Remove 10 items from the list and display the signature.

for( Count = 10; Count >= 1; Count -= 1 )

{

pListEntry = InterlockedPopEntrySList(pListHead);

if( NULL == pListEntry )

{

printf("List is empty./n");

return -1;

}

pProgramItem = (PPROGRAM_ITEM)pListEntry;

printf("Signature is %d/n", pProgramItem->Signature);

// This example assumes that the SLIST_ENTRY structure is the

// first member of the structure. If your structure does not

// follow this convention, you must compute the starting address

// of the structure before calling the free function.

_aligned_free(pListEntry);

}

// Flush the list and verify that the items are gone.

pListEntry = InterlockedFlushSList(pListHead);

pFirstEntry = InterlockedPopEntrySList(pListHead);

if (pFirstEntry != NULL)

{

printf("Error: List is not empty./n");

return -1;

}

_aligned_free(pListHead);

return 1;

}

分享到:
评论

相关推荐

    api-ms-win-core-interlocked-l1-1-0.dll

    api-ms-win-core-interlocked-l1-1-0

    API-MS-WIN一系列丢失DLL打包

    api-ms-win-core-interlocked-l1-1-0.dll api-ms-win-core-libraryloader-l1-1-0.dll api-ms-win-core-localization-l1-2-0.dll api-ms-win-core-memory-l1-1-0.dll api-ms-win-core-namedpipe-l1-1-0.dll api-ms-...

    Windows下实现的读写锁(VS2008环境)

    WIN环境下实现的轻量级读写锁,效率还过得去,C++代码使用Interlocked系列函数实现。

    C#中使用Interlocked进行原子操作的技巧

    使用.NET提供的Interlocked类可以对一些数据进行原子操作,看起来似乎跟lock锁一样,但它并不是lock锁,它的原子操作是基于CPU本身的,非阻塞的,所以要比lock的效率高

    ExampleLock.zip

    C#控制台示例代码,C#代码处理并发问题,悲观并发实例-C#中使用Interlocked原子操作处理并发,控制台直接运行调式。

    An SEU-hardened latch with a triple-interlocked structure

    A single event upset (SEU) tolerant latch with a triple-interlocked structure is presented. Its self-recovery mechanism is implemented by using three pairs of guard-gates and inverters to construct ...

    线程同步的6种方式的代码

    常用的线程锁分为一下七种:volatile关键字、Lock锁、System.Threading.Interlocked原子级别操作、Monitor、Metux、ReaderWriterLock、EventWaitHandle同步事件。此次代码中包含了以上除了volatile的测试代码

    深入多线程之:深入分析Interlocked

    在大多数计算机上,增加变量操作不是一个原子操作,需要执行下列步骤:  一:将实例变量中的值加载到寄存器中。  二:增加或减少该值。  三:在实例变量中存储该值。... Interlocked.Decrement以原子操作的形式递减

    .NET中保证线程安全的高级方法Interlocked类使用介绍

    主要介绍了.NET中保证线程安全的高级方法Interlocked类使用介绍,Interlocked类可以为为多个线程共享的变量提供原子操作,需要的朋友可以参考下

    howto_interlocked_circles_use_uncleess_zip_

    interlocked circles code

    C#使用Interlocked实现线程同步

    今天小编就为大家分享一篇关于C#使用Interlocked实现线程同步,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

    Silverlight2.0功能展示Demo源码

    Interlocked - 为多个线程共享的变量提供原子级的操作 EventWaitHandle - 通知其他线程是否可入的类 Monitor - 提供同步访问对象的机制 ThreadStaticAttribute - 所指定的静态变量对每个线程都是唯一的 25、...

    高清中文版-mips指令基础

    IPS (an acronym for Microprocessor without Interlocked Pipeline Stages) is a reduced instruction set computer (RISC) instruction set architecture (ISA)[1]:A-1[2]:19 developed by MIPS Technologies ...

    c# 线程(thread)同步处理

    .NET平台上的线程同步的问题线程之间共享的变量访问的同步,它的操作时原子操作,且被线程共享.你可以通过Interlocked.Increment 或 Interlocked.Decrement来增加或减少共享变量.它的有点在于是原子操作,也就是说...

Global site tag (gtag.js) - Google Analytics