场景:
1. 多线程编程时,有时候需要统计某个变量或对象的创建个数或者是根据某个变量值来判断是否需要继续执行下去,这时候互锁函数是比较高效的方案之一了。
说明:
1.原子访问:(互锁函数族)
-- 原子访问,指线程在访问资源时能够确保所有其他线程都不在同一时间内访问相同的资源.
-- 调用一个互锁函数通常只需要执行几个CPU周期(通常小于50),并且不需要从用户模式转换为内核模式(通常这需要1000个CPU周期).
-- 互锁函数是CPU硬件支持的,如果是x86处理器,互锁函数会向总线发出一个硬件信号,防止其他处理器访问同一个内存地址.
-- 无论编译器怎么生成代码,无论计算机中安装了多少个处理器,都能那个保证以原子操作方式来修改一个值.
-- 必须保证传递给这个函数的变量地址正确的对齐,否则这些函数就会运行失败.
(1) CPU处理准确对齐的数据时,它的运行效率最高.在用数据的大小对内存地址取模,结果为0时,数据是对齐的。例如,WORD类型的值
应该总是从能够被2除尽的地址开始,而DWORD类型的值则应该总是从能够被4除尽的地址开始.
test_interlock.cpp
// test_interlock.cpp : 定义控制台应用程序的入口点。 // 原子访问: 互锁的函数家族. #include "stdafx.h" #include <Windows.h> #include <stdint.h> #include <assert.h> #include <iostream> using namespace std; static int32_t gCount = 0; static int32_t gExecuteCount = 0; static const int kThreadNum = 10; static const int kLoopNum = 1000; static uint32_t setted = 0; #define APR_ALIGN(size, boundary) (((size) + ((boundary) - 1)) & ~((boundary) - 1)) DWORD WINAPI ThreadFunc(PVOID pvParam) { long* g_x = (long*)pvParam; for(int i = 0; i< kLoopNum; ++i) { //cout << "sync_func CurrentThreadID: " << GetCurrentThreadId() << endl; InterlockedExchangeAdd(g_x,1); InterlockedExchange(&setted,i%2); //1.让其他线程也有机会执行. Sleep(10); } return 0; } void TestInterlockedExchangeAdd() { HANDLE hThreads[kThreadNum]; //《Windows核心编程》说地址要对齐,虽然x86会额外做对齐的指令操作. // 但是能自己对齐还是自己对齐吧.比如AMD cpu不对齐可能会出现问题. long g_x = 0; for(int i = 0; i< kThreadNum; ++i) { DWORD dwThreadID; hThreads[i] = CreateThread(NULL,0,ThreadFunc,&g_x,0,&dwThreadID); } DWORD rc = WaitForMultipleObjects(kThreadNum, hThreads, TRUE, INFINITE); assert(rc == WAIT_OBJECT_0); for(int i = 0; i< kThreadNum; ++i) { CloseHandle(hThreads[i]); } assert(g_x == 10000); assert(setted == 1); } int _tmain(int argc, _TCHAR* argv[]) { TestInterlockedExchangeAdd(); return 0; }
[并发并行]_[线程同步]_[Windows用户态下的原子访问的互锁函数]
原文:http://blog.csdn.net/infoworld/article/details/43982877