自写临界区

单行代码原子操作

在这里插入图片描述

多核指令的执行过程

一条指令的执行过程是: CPU先读取指令到CPU内部,然后才是执行该指令。而在多核多线程的情况下。可能出现多个CPU同时读到了同一条指令,这样线程就会出问题。 那么解决访问是,限制CPU读取指令,只能有一个CPU读取同一条指令,该操作成为原子操作。
LOCK 就可以对一个内存加锁,同一时刻只能有一个CPU来读取该内存的指令。

使用临界区,互斥体也可以解决多线程安全问题,但是效率太低。例如临界区,是一个线程进入临界区后把其他线程给挂起来,执行完后再恢复其他线程。这样会对CPU性能造成很大的影响。
而如果把代码改成对访问的公共内存加锁,这样就可以提高效率。还能保证多线程安全不会出问题。

for (int i=0;i<10000000;i++)
	{
		__asm {
			lea eax, a    //这里使用取地址,就是为了对内存加锁  而不能用mov  eax,a  对寄存器加锁是没有意义的,因为多核情况下有多个eax寄存器.
			lock inc dword ptr ds : [eax]  //这里限制了,在同一时刻只能有一个CPU执行这一行代码,去掉lock就会发生问题
			//inc dword ptr ds : [eax]  如果写成这样,单核是安全的 ,多核就会出现问题,可能有两个CPU同时把读取了a的值,读取的时候是一样的值,而执行完这条指令,结果只+1。
		}
	}

临界资源

全局变量,文件 这种不能让多个CPU同时来操作的资源就是临界资源。

多行代码原子操作

自己实现临界区


#include <windows.h>
#include <stdio.h>

DWORD dwFlag = 0;

 __declspec(naked) void  ScritiSection()
{
	__asm {

	start:	mov eax, 1
		lock	xadd[dwFlag], eax    //必须要使用这种读取值,和设置值在一条指令实现的汇编指令。
		cmp eax, 0
		jz endLab
		lock	dec[dwFlag]         
	}
	Sleep(1);

	__asm {

		jmp start
	EndLab:
	ret	
	}
}
void LeaveSecritiSection()
{
	__asm {
		lock	dec[dwFlag]
	}

}

int a = 0;
void fun1(void* p)
{
	for (int i = 0; i < 1000011; i++)
	{
		ScritiSection();
		a++;   //临界区代码    访问临界资源
		LeaveSecritiSection();
	}
}

void fun2(void* p)
{
	for (int i = 0; i < 1000000; i++)
	{
		ScritiSection();
		a++;
		LeaveSecritiSection();

	}
}
int main(int argc, char * argv[])
{
	DWORD tid1;
	DWORD tid2;
	HANDLE hThread[2] = { 0 };
	hThread[0]=CreateThread(0, 0, (LPTHREAD_START_ROUTINE)fun1, 0, 0, &tid1);
	hThread[1] = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)fun2, 0, 0,&tid2);
	WaitForMultipleObjectsEx(2, hThread,TRUE,INFINITE,0);
	printf("a=%d\n", a);
	getchar();
	return 0;
}

总结:

临界区的本质就是线程切换(Sleep的本质就是主动切换线程),非常消耗资源。更加轻量级,效率更高的解决方案是使用自旋锁。

c builder线程临界区(critical section)指的是在并发编程中,多个线程同时操作共享的数据时,需要保证某些代码段在同一时刻只能由一个线程执行,否则可能会产生竞态条件(race condition)。在c builder中,通过使用锁机制(包括互斥锁、读锁、信号量等)来实现线程临界区的保护。 临界区的设置需要考虑多个方面,例如:哪些代码段需要保护、保护的临界区是否越小越好、保护的代价是否过高等。一般来说,临界区应尽量小,以减少锁的持有时间,提高并发效率;同时,需要注意临界区的合理设置,以防止死锁等并发编程常见问题的发生。 在c builder中,通过使用相关锁机制实现线程临界区的保护,例如: - 使用互斥锁(TMutex):在一个线程进入临界区时获取互斥锁并加锁,其他线程需要等待锁被释放后才能进入,执行完临界区代码后释放锁。 - 使用读锁(TMultiReadExclusiveWriteSynchronizer):在读操作时多个线程可以同时访问临界区,但在操作时只能有一个线程操作,其他线程需要等待。可以提高读操作的并发性能。 - 使用信号量(TSemaphore):通过设置可访问的线程数目,限定同时可以访问临界区的线程数量,保证对共享数据的顺序和正确性。 综上所述,对于c builder中的线程临界区,需要根据具体的场景选择合适的锁机制来进行保护,以确保共享数据的正确性和并发性能的提高。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值