在计算机中,原子操作又称为原语,操作系统保证:原子操作是不可分割的,在执行完毕之前不会被任何其它任务或事件中断。
下面列出一些常用的Interlocked系列函数:
InterlockedIncrement自增
/** \brief 实现数的原子性自减
*
* \param lpAddend 指向要递增的变量的指针
* \return 返回自增后的变量值
*
*/
LONG InterlockedIncrement(LPLONG lpAddend);
在C中相当于
int i = 0;
i++;
为了保证原子性,应
InterlockedIncrement((long*)&i);
举个例子:如果一个变量 long value =0;
首先说一下正常情况下的加减操作:value+=1;
1:系统从Value的空间取出值,并动态生成一个空间来存储取出来的值;
2:将取出来的值和1作加法,并且将和放回Value的空间覆盖掉原值。加法结束。
如果此时有两个Thread ,分别记作threadA,threadB。
1:threadA将Value从存储空间取出,为0;
2:threadB将Value从存储空间取出,为0;
3:threadA将取出来的值和1作加法,并且将和放回Value的空间覆盖掉原值。加法结束,Value=1。
4:threadB将取出来的值和1作加法,并且将和放回Value的空间覆盖掉原值。加法结束,Value=1。
最后Value =1 ,而正确应该是2;这就是问题的所在,InterlockedIncrement能够保证在一个线程访问变量时其它线程不能访问。同理InterlockedDecrement。
InterlockedDecrement自减
/** \brief 实现数的原子性自增
*
* \param lpAddend 指向要递减的变量的指针
* \return 返回自减后的变量值
*
*/
LONG InterlockedDecrement(LPLONG lpAddend);
在C中相当于
int i = 0;
i--;
为了保证原子性,应
InterlockedDecrement((long*)&i);
InterlockedExchangeAdd加减
/** \brief 实现数的原子性自增
*
* \param Addend 指向要加减的变量的指针
* \param Increment 要加减的值
* \return 返回变量值
*
*/
LONG InterlockedExchangeAdd(LPLONG Addend, LONG Increment);
示例
InterlockedExchangeAdd((long*)&i, 5);//等价于 i = i + 5;
InterlockedExchange赋值
/** \brief 实现数的原子性赋值
*
* \param Addend 指向要赋值的变量的指针
* \param Value 要加减的值
* \return 返回变量值
*
*/
LONG InterlockedExchange(LPLONG Addend, LONG Value);
示例
InterlockedExchange((long*)&i, 10);//等价于 i = 5;
示例
模拟用户登录(线程),登录一次则记录一次,最终输出有多少个用户登录的多少次。
#include <stdio.h>
#include <Windows.h>
#include <process.h>
#define THREAD_COUNT 10U //用户数
void Thread(void*);
volatile int count = 0;//记录登录的次数
int main()
{
HANDLE th[THREAD_COUNT] = { 0 };
int num = 30;
//模拟次数
while (num--)
{
count = 0;//重置登录次数
for (size_t i = 0; i < THREAD_COUNT; i++)
{
/* 创建线程 */
th[i] = _beginthread(Thread, 0, NULL);
}
//等待所有线程结束
WaitForMultipleObjects(THREAD_COUNT, th, TRUE, INFINITE);
printf("共 %d 个用户 最终登录的次数为%d\n", THREAD_COUNT, count);
}
return 0;
}
void Thread(void* arg)
{
Sleep(100);
count++;
}
输出结果
输出结果把变量自增操作封装为原子性操作
#include <stdio.h>
#include <Windows.h>
#include <process.h>
#define THREAD_COUNT 10U //用户数
void Thread(void*);
volatile int count = 0;//记录登录的次数
int main()
{
HANDLE th[THREAD_COUNT] = { 0 };
int num = 30;
//模拟次数
while (num--)
{
count = 0;//重置登录次数
for (size_t i = 0; i < THREAD_COUNT; i++)
{
/* 创建线程 */
th[i] = _beginthread(Thread, 0, NULL);
}
//等待所有线程结束
WaitForMultipleObjects(THREAD_COUNT, th, TRUE, INFINITE);
printf("共 %d 个用户 最终登录的次数为%d\n", THREAD_COUNT, count);
}
return 0;
}
void Thread(void* arg)
{
Sleep(100);
//count++;
InterlockedIncrement((long*)&count);
}
输出结果