Windows多线程编程(7)--原子操作
来源:互联网 发布:js数组的map方法 编辑:程序博客网 时间:2024/05/23 00:07
今天介绍一种低层次的多线程同步机制--原子操作(Atomic operation)。原子操作保证同一时间只能有一个线程对某个变量进行操作。通常一条C/C++语句对应多个汇编指令,而处理器的中断可能发生在任意一条汇编指令处。因此,当一个线程访问某个变量时,可能会有另一个线程也在访问,这就造成了数据的不一致。
下面给出一个例子。
#include <Windows.h>#include <iostream> DWORD WINAPI ThreadFunc(LPVOID p);int num = 0; int main(int argc, char **argv){ for (int t = 0; t < 100; t++) { num = 0; const int N = 20; HANDLE hThreadArray[N]; for (int i = 0; i < N; i++) { hThreadArray[i] = CreateThread(NULL, 0, ThreadFunc, (LPVOID)i, 0, NULL); } WaitForMultipleObjects(N, hThreadArray, TRUE, INFINITE); for (int i = 0; i < N; i++) { CloseHandle(hThreadArray[i]); } std::cout << "num = " << num << std::endl; } return 0;} DWORD WINAPI ThreadFunc(LPVOID p){ Sleep(10); num++; Sleep(10); num--; Sleep(10); num++; return 0;}
上面的程序每次启动20个子线程,每个子线程对全局变量num加1。模拟100次,程序运行结果并不总是20。这是因为ThreadFunc中的num++和num--操作不是原子操作,在执行的过程中发生了中断。
下面是我的计算机的运行结果。
为了实现变量操作的同步,Windows提供了一系列原子操作函数。下面详细介绍这些函数。
1. InterlockedIncrement:指定的LONG型变量增加1
WINBASEAPILONGWINAPIInterlockedIncrement ( __inout LONG volatile *lpAddend );
lpAddend:指向自增变量的指针。
返回值:返回自增后的值。
LONG定义在头文件WinNT.h中,如下所示。
#ifndef VOID#define VOID voidtypedef char CHAR;typedef short SHORT;typedef long LONG;#if !defined(MIDL_PASS)typedef int INT;#endif#endif2. InterlockedDecrement:指定的LONG型变量减少1
WINBASEAPILONGWINAPIInterlockedDecrement ( __inout LONG volatile *lpAddend );
lpAddend:指向自减变量的指针。
返回值:返回自减后的值。
WINBASEAPILONGWINAPIInterlockedExchange ( __inout LONG volatile *Target, __in LONG Value );
Target:指向赋值变量的指针。
Value:赋给Target指向变量的值。
返回值:返回未赋值之前Target指向的变量的值。
当我们需要对指针赋值时,可以用InterlockedExchangePointer函数。它其实是一个基于InterlockedExchange函数的宏。这是因为对于32位程序,指针就是一个LONG型的变量。
#define InterlockedExchangePointer(Target, Value) \ (PVOID)InterlockedExchange((PLONG)(Target), (LONG)(Value))
WINBASEAPILONGWINAPIInterlockedExchangeAdd ( __inout LONG volatile *Addend, __in LONG Value );
Addend:指向LONG型变量的指针。
Value:加数。执行后,*Addend += Value。
返回值:返回未做加法之前,Addend指向的变量的值。
WINBASEAPILONGWINAPIInterlockedCompareExchange ( __inout LONG volatile *Destination, __in LONG Exchange, __in LONG Comperand );
如果 *Destination == Comperand,*Destination = Exchange;否则,不执行任何操作。
返回值:*Destination未修改之前的值。
对于高版本的Windows,还定义了LONGLONG类型的InterlockedCompareExchange64函数,如下所示。
#if (_WIN32_WINNT >= 0x0502) WINBASEAPILONGLONGWINAPIInterlockedCompareExchange64 ( __inout LONGLONG volatile *Destination, __in LONGLONG Exchange, __in LONGLONG Comperand ); #endif然后基于该函数,又定义了3个位运算函数(And,Or,Xor)和上述1~4个函数的LONGLONG类型的版本。我们仅以And函数位列,列出代码。
FORCEINLINELONGLONGInterlockedAnd64 ( __inout LONGLONG volatile *Destination, __in LONGLONG Value ){ LONGLONG Old; do { Old = *Destination; } while (InterlockedCompareExchange64(Destination, Old & Value, Old) != Old); return Old;}最后,当我们使用C++语言的时候,Windows对以上函数进行了重载,从而支持其它类型的变量。我们仅以InterlockedIncrement函数为例,列出在WinBase.h文件中的相关代码。
#if defined(__cplusplus) /* { */ extern "C++" { FORCEINLINEunsignedInterlockedIncrement( __inout __drv_interlocked unsigned volatile *Addend ){ return (unsigned) InterlockedIncrement((volatile long*) Addend);} FORCEINLINEunsigned longInterlockedIncrement( __inout __drv_interlocked unsigned long volatile *Addend ){ return (unsigned long) InterlockedIncrement((volatile long*) Addend);}
原文:http://hi.baidu.com/herohbc/item/61c973eddbecb0216dabb805
- Windows多线程编程(7)--原子操作
- windows多线程--原子操作
- windows多线程--原子操作
- 【windows多线程】原子操作 Interlocked系列函数
- Windows并发&异步编程(2)原子操作Interlocked
- Java多线程编程--(6)学习Java5.0 并发编程包--原子操作的一些类型
- Java多线程-(6)java 原子操作
- 多线程----原子操作
- 多线程之原子操作
- 多线程与原子操作
- 多线程 之原子操作
- 多线程-原子操作
- 多线程-原子操作
- 多线程原子操作:AtomicBoolean
- C# 多线程--原子操作
- 《多线程编程中的原子操作》读后小结
- Windows API 原子操作
- 《windows核心编程》读后编码--原子操作
- 备份
- 生命力最强的新闻,放到二十年后依旧是新闻
- (转)IOS自定义UITabBar
- IOS开发实用工具
- 网络编程学习_简单的多进程并发服务器/客户端
- Windows多线程编程(7)--原子操作
- hdu 3487 Play with Chain(Splay)
- NYOJ 658 字符串右移
- 浅谈oracle中重建索引
- 黑马程序员-----银行业务调度系统总结*
- ThinkPHP 统计查询
- 计划都是屁,一样也完不成
- Windows环境下Android NDK环境搭建
- Java程序开发中需要注意的内存问题