请问线程安全的汇编原理

请教线程安全的汇编原理
我记得有一个线程非安全的例子,就是多个线程对同一个全局变量进行++操作,最终这个全局变量的值不符合我们的预期。

想请教一下各位汇编高人,从汇编的角度看,这个++操作的结果为啥不符合我们的预期? 

希望能给出汇编语句,并简单解释一下原因,多谢!

------解决方案--------------------
可能是线程同步的问题吧
------解决方案--------------------
线程可以在任何地方被windows打断,但是只能在两条指令之间被打断,因为指令是CPU执行的最小单位。举个例子:
.data?
dwCounter dd ?
...

.code
...
Counter proc ebx esi edi,lParam
mov eax,dwCounter
inc eax
mov dwCounter,eax
ret
Counter endp
Counter是一个线程函数,多次执行后,假如线程A执行时在ine eax和mov dwCounter,eax之间被挂起,下一个线程B的执行又将eax的值修改,等轮到线程A再次执行mov dwCounter,eax时,eax的值已经被线程B修改了,结果当然不是预期的,不知道楼主问的是不是这个。
------解决方案--------------------
假如Number是一个全局变量;有函数如下:
void Foo()
{
number++;
//做一些事情;
number--;
};运行这个函数之后,要保持Numbers数值不变;在多线程的情况下,就不能保证了;
将Number++反汇编之后:
mov eax,【number】
add eax,1
mov [number],eax
将Number--反汇编之后:
mov ecx,dword ptr [number]
sub ecx,1
mov dword ptr [number],ecx
如果在多线程的环境下,同时运行两个Foo函数,就有可能导致汇编指令交错在一起,出现下面的情况:
假设Foo1,Foo2都是上面的函数
Foo1将number取出后加1再保存;Foo2也将number取出后加在保存;然后Foo1在去将number减一的动作;foo2也做number减1的动作;
这样foo1和foo2都不能保持原先的number值
------解决方案--------------------
会是中断引起的吗?
------解决方案--------------------
这个是线程同步问题
在多线程中访问共享资源时,需要使用信号量或互斥锁实现线程同步,在Windows中还可以使用临界区;
如:i=1
在线程1中执行i++,希望的结果是2,但是在进入线程1时,有可能其它进程先执行了i++操作,则得出的结果有可能是3或其它值;
所以此时的线程函数,应写成如下形式:
void thread_func(void *arg)
{
pthread_mutex_lock(&mutex);

// 访问共享资源的代码

pthread_mutex_unlock(&mutex);

}

从arm汇编角度来说,信号量,互斥锁或临界区在底层都是依靠信号量操作指令swp,来实现原子操作的;
所谓原子操作就是在一条指令中完成信号量的读取和修改操作;

如果使用str和ldr指令完成寄存器与内存单元的数据交换,需要如下指令:
ldr r2, [r1] # [r1] -> r2
str r0, [r1] # r0 -> [r1]
mov r0, r2 # r2 -> r0
这样的操作显然不能满足原子操作的要求,因为在多线程中这是有可能被强占的操作;

而swp指令可以在一条指令中完成数据的修改和读取操作:
swp r0, r0, [r1] # r0中的内容与和r1指向的内存单元进行交换

如果用-1表示有线程在试锁,0表示锁被占用,1表示可以获得锁,则可以用如下操作完成互斥:
mvn r1, #0 # 将-1保存到r1中
spin:
swp r2, r1, [r0] # r1-> [r0], [r0] -> r2
cmn r2, #1 # 判断读取到的信号量是否为-1
beq spin # 如果是-1,表示其它进程正在访问该信号量,跳转到spin或进入睡眠

cmp r2, #0 # 判断读取到的信号量是否为0
beq spin # 如果是0,表示锁已被占用,跳转到spin进行自旋操作或进入睡眠

mov r2, #0 # 此时锁可以被获得
str r2, [r0] # [r0] = 0,占有锁,在解锁时恢复为1

上述是用arm汇编实现的线程同步,代码比较简单,真正的同步操作要比这个复杂
 





------解决方案--------------------
这是线程的机制,不关语言的事。。。。不管是c还是汇编还是什么别的语言写的线程。。

------解决方案--------------------
++操作会编译成多条汇编指令,而不是一条原子指令,所以就不是线程安全的了