编程william hill官网
直播中

大学生电子

15年用户 2894经验值
私信 关注
[问答]

windows多线程编程碰到一个问题,请编程高手分析?

windows多线程编程碰到一个问题,请编程高手分析?
在VC中多线程编程中有一个数据保护问题,如果一个全局变量被多个线程访问,那么它必须被保护,以确保它的值可靠。例如下面一个例子,一个多线程程序在多个线程中对全局整型counter变量的值进行累加。
count = count + 1;
这段代码按照下列CPU指令顺序执行的:
1.将变量值移入处理器的寄存器中
2.增加寄存器中的变量值
3.把寄存器中的变量值写回count变量
由于操作系统可能在线程运行过程中的任意时刻打断线程,所以执行这些指令的两个线程可能按照如下的顺序进行(假设count初始值为5):
线程1:将count变量的值移到寄存器中。(count=5,寄存器=5),然后切换到线程2(count=5,寄存器未知)。
线程2:将count变量的值移到寄存器中(count=5,寄存器=5)。
线程2: 增加寄存器中的值(count=5,寄存器=6)。
线程2: 将寄存器中的值写回count变量(count=6,寄存器=6),然后切换回线程1.(count=6,寄存器=5)。
线程1: 增加寄存器的值。(count=6,寄存器=6)。
线程1: 将寄存器中的值写回count变量(count = 6, register = 6)。
由于线程1在增加变量值并将其写回之前被打断,所以变量count的值被设为6而不是7。
操作系统为系统中地每一个线程的寄存器都保存了副本。即使编写了count++这样的代码,用户还是会遇到相同的问题,因为处理器会将代码按照多条指令执行。

单片机程序中(无操作系统情况)是否也会出现这种问题?
主程序和中断子程序都执行count = count + 1;
主程序:将count变量的值移到寄存器中。(count=5,寄存器=5),
* 此时发生中断,保护断点切换到中断子程序,保护现场,之后中断的(count=5,寄存器未知)。
中断子程序:将count变量的值移到寄存器中(count=5,寄存器=5)。
中断子程序: 增加寄存器中的值(count=5,寄存器=6)。
中断子程序: 将寄存器中的值写回count变量(count=6,寄存器=6),
* 此时中断返回:恢复现场,然后恢复断点返回主程序,主程序的(count=6,寄存器=5)。
主程序: 增加寄存器的值。(count=6,寄存器=6)。
主程序: 将寄存器中的值写回count变量(count = 6, register = 6)。
结果出现和windows编程中多线程同样的问题,count 的值是6而不是7。
如何避免上面的情况发生?也就是最后使count的结果为7,谢谢!

回帖(1)

电子工程师

2011-3-11 17:42:03
这个是基本常识,什么CPU,MCU都有这样的问题

1 单片机的每个RAM在任意时刻其值都要用指令去操做才会改变.中断发生后MCU硬件只把当前地址自动存到堆栈区中.某些架构的MCU堆栈与RAM共用(比如51/6502),某些则是单独且只能被硬体操做(比如PIC).
2 以上你所说的单片机的过程都要由软件才能实现.这个你可以从反汇编窗口看出.

楼主对cpu中断保护现场理解有误。
“中断子程序:将count变量的值移到寄存器中(count=5,寄存器=5)。”保护现场没有这个动作,中断保护的是可能被中断程序改写的寄存器内容,count变量值不会放在放在寄存器中,寄存器放的是运算过程中的临时变量。保护现场没必要将count变量的值移到寄存器中保护。

"恢复现场"单片机基本就是手动的,只有“保护断点”是硬件自动完成成的。
"恢复现场"用汇编都要程序员自己编程的,虽然C不用,但也是编译器生成的。

可以认为单片机的程序前台和后台就是两个线程,所以你说的在WINDOWS编程中会遇到的问题在这里也会遇得到的。
解决的方法有很多:
1、如果变量是作为标志位使用,那么尽量使用char类型,这样访问的时候就具有原子操作了。
2、在访问之前禁止中断位。
3、如果所使用的变量不具备原子操作的属性,那么在前台程序中可以多次读取该变量然后在进行比较以判断操作的安全性。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分