C++原子操作之windows

在多线程环境下要计数,需要保证:计数变量的一致性和线程安全才能保证多线程环境下计数正确。
现在就来简短的说一说windows的C++原子操作。

——-所谓原子访问,指的是一个线程在访问某个资源的同时能够保证没有其他线程会在同一时刻访问同一资源。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周期以上)。

InterlockedExchangeAdd提供保证long类型的原子操作。
InterlockedExchangeAdd64提供long long 64位的原子操作。
这两个函数用于加操作,用法如下:
long i=0;
InterlockedExchangeAdd(&i,1);//加1
InterlockedExchangeAdd(&i,3);//加3

下面的几个函数是讲参数变为指定的值(原子操作)。
InterlockedExchange
InterlockedExchange64
InterlockedExchangePointer//如果应用程序是32位,那么这里替换的就是32位,64位程序则对应
在实现旋转锁时,InterlockedExchange函数极其有用:

//标识一个共享资源是否正在被使用的全局变量
BOOL g_fResourceInUse = FALSE;
...
void ASCEFunc()
{
         //等待访问共享资源
         while(InterlockedExchange(&g_fResourceInUse, TRUE) == TRUE)
                   Sleep(1);
         //访问共享资源
         ...
         //结束访问
         InterlockedExchange(&g_fResourceInUse, FALSE);
}

注意,在使用这项技术时要小心,因为旋转锁会耗费CPU时间。特别是在单CPU机器上应该避免使用旋转锁,如果一个线程不停地循环,那么这会浪费宝贵的CPU时间,而且会阻止其他线程改变该锁的值。
Interlocked系列函数还剩下下面2个,功能是以原子操作方式进行对比和设置。
InterlockedCompareExchange
InterlockedCompareExchangePointer
这两个函数以原子方式执行一个测试和设置操作。对32位应用程序来说,这两个函数都对32位值进行操作;在64位应用程序中,InterlockedCompareExchange对32位值进行操作而InterlockedCompareExchangePointer对64位值进行操作。函数会将当前值(Destination指向的)与参数Comparand进行比较,如果两个值相同,那么函数会将*Destination修改为Exchange参数指定的值。若不等,则*Destination保持不变。函数会返回*Destination原来的值。所有这些操作都是一个原子执行单元来完成的。
对函数体感兴趣的朋友可以参考https://blog.csdn.net/kingswb/article/details/51326461这个里面的内容。

猜你喜欢

转载自blog.csdn.net/liyu123__/article/details/80985744