当前位置:首页 > > 充电吧
[导读]所谓原子访问,指的是一个线程在访问某个资源的同时能够保证没有其他线程会在同一时刻访问同一资源。Interlocked系列函数提供了这样的操作。所有这些函数会以原子方式来操控一个值。Interlocke

所谓原子访问,指的是一个线程在访问某个资源的同时能够保证没有其他线程会在同一时刻访问同一资源。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),而且不需要在用户模式和内核模式之间进行切换(这个切换通常需要占用1000个CPU周期以上)。

 

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

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

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

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

);

 

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

  __inout  LONGLONG volatile *Addend,

  __in     LONGLONG Value

);

 

2)InterlockedExchange函数用于原子地将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位应用程序中,InterlockedCompareExchange对32位值进行操作而InterlockedCompareExchangePointer对64位值进行操作。函数会将当前值(Destination指向的)与参数Comparand进行比较,如果两个值相同,那么函数会将*Destination修改为Exchange参数指定的值。若不等,则*Destination保持不变。函数会返回*Destination原来的值。所有这些操作都是一个原子执行单元来完成的。

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

LONGLONG __cdecl InterlockedCompareExchange64(

  __inout  LONGLONG volatile *Destination,

  __in     LONGLONG Exchange,

  __in     LONGLONG Comparand

);

 

4)Interlocked单向链表函数

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 

#include 

#include 

 

// 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;

}


本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭