1.临界区

xiaoxiao2025-08-31  9

临界区:一次只允许一个线程进入直到离开

并发是指多个线程在同时执行:

单核–(是分时执行,不是真正的同时)多核–(在某一个时刻,会同时有多个线程再执行)

同步则是保证在并发执行的环境中各个线程可以有序的执行

分析两条线程执行下面代码。

DWORD dwVal =0; //全局变量

线程中的代码:

dwVal ++; //只有一行安全吗?

对应的汇编代码:

mov eax,[0x12345678] add eax,1 mov [0x12345678],eax

如果在执行完 add eax,1 后产生了线程切换(系统时钟),第二个线程进来了:mov eax,[0x12345678] add eax,1 mov [0x12345678],eax; 第二个线程已经把1写到全局变量里了,第一个线程突然恢复执行mov [0x12345678],eax写入全局变量里的值还是1。

两线程有序执行结果应该为2,但是它在执行完 add eax,1 后,产生了线程切换得到的数据是错误的。



继续上面把上面的3行汇编换成一行看看是否安全。

inc dword ptr ds:[0x12345678]

如果你的CPU是单核这样的解决方案是安全的,如果你当前的CPU是多核的可能会出现一种极端情况,两个CPU同时执行同一行代码。

将以上代码修改成

lock inc dword ptr ds:[0x12345678] //多核多线程下 依旧安全

lock锁住了当前指令所在的那块内存,用了lock在某个时刻只能有一个CPU来读这块内存。

参考: kernel32.Interlockedincrement 原子操作相关的API:

Interlockedlncrement InterlockedExchangeAdd InterlockedFlushSList InterlockedDecrement InterlockedExchange InterlockedPopEntrySList InterlockedCompareExchange InterlockedPushEntrySList

多行代码原子操作

关键代码A //N行代码要求原子操作 关键代码B //单独加LOCK可以吗? 关键代码C

如果你的逻辑代码有很多行的话,每个关键代码加lock是没有办法保证的的代码逻辑是正确的。

临界区:一次只允许一个线程进入直到离开

DWORD dwFlag = 0; //11实现临界区的方式就是加锁 //锁:全局变量进去加1 出去减1 if(dwFlag == 0)//判断临界区是否处于打开状态 { dwFlag = 1; //进入临界区 ... dwFlag = 0; //离开临界区 }

上面的临界区是不安全的,比如线程1判断完临界区是可以进入的,还没有将临界区置1线程切换了,这样就会出现线程1和2同时进入临界区。

自己实现临界区 全局变量: Flag =0

进入临界区: mov eax,1 lock xadd [Flag],eax cmp eax,0 //如果不是0就是有人进入临界区了 jz endLab dec [Flag] //减1 让当前线程等待Sleep.. endLab: ret 离开临界区: lock dec[Flag]
转载请注明原文地址: https://www.6miu.com/read-5035518.html

最新回复(0)