【C语言】Windows下的多线程编程-原子操作

在计算机中,原子操作又称为原语,操作系统保证:原子操作是不可分割的,在执行完毕之前不会被任何其它任务或事件中断。

下面列出一些常用的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);
}

输出结果
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值