打印

从windows多线程编程想到一个问题,请大侠帮忙分析?

[复制链接]
6507|44
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
okay007|  楼主 | 2010-12-25 00:55 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 okay007 于 2010-12-26 10:13 编辑

在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,谢谢!

相关帖子

沙发
李冬发| | 2010-12-25 01:18 | 只看该作者
所以有个原子操作的问题。

使用特权

评论回复
板凳
okay007|  楼主 | 2010-12-25 01:48 | 只看该作者
可以更详细一点吗?谢谢!

使用特权

评论回复
地板
ayb_ice| | 2010-12-25 08:24 | 只看该作者
这个是基本常识,什么CPU,MCU都有这样的问题

使用特权

评论回复
5
okay007|  楼主 | 2010-12-25 10:40 | 只看该作者
那也就是CPU在设计时已经解决了?我们在单片机编程时可以不用考虑了?
我只知道在windows多线程编程中要编程人员自己解决。
在单片机中只用过C,也没有关注过这种问题,才有此一问!

使用特权

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

使用特权

评论回复
7
okay007|  楼主 | 2010-12-25 17:23 | 只看该作者
1 单片机的每个RAM在任意时刻其值都要用指令去操做才会改变.中断发生后MCU硬件只把当前地址自动存到堆栈区中.某些架构的MCU堆栈与RAM共用(比如51/6502),某些则是单独且只能被硬体操做(比如PIC).
2 以上你所说的单片 ...
sz_walter 发表于 2010-12-25 16:37

你所说的我都知道,
我主要想知道,如何避免楼主位在单片机中断返回后count的结果为6?正常应该为7,用汇编或C,谢谢!

使用特权

评论回复
8
xuyaqi| | 2010-12-25 17:37 | 只看该作者
楼主对cpu中断保护现场理解有误。
“中断子程序:将count变量的值移到寄存器中(count=5,寄存器=5)。”保护现场没有这个动作,中断保护的是可能被中断程序改写的寄存器内容,count变量值不会放在放在寄存器中,寄存器放的是运算过程中的临时变量。保护现场没必要将count变量的值移到寄存器中保护。

使用特权

评论回复
9
okay007|  楼主 | 2010-12-25 18:03 | 只看该作者
本帖最后由 okay007 于 2010-12-25 18:09 编辑

不好意思,请详细看题:
* 此时发生中断,保护断点,然后切换到中断子程序保护现场,之后,中断的(count=5,寄存器未知)。
* 中断子程序:将count变量的值移到寄存器中(count=5,寄存器=5)。(上句中已经保护了现场,此句是中断中自己编的代码)。

我主要想知道,如何避免楼主位在单片机中断返回后count的结果为6?正常应该为7,用汇编或C,谢谢!

使用特权

评论回复
10
xuyaqi| | 2010-12-25 20:02 | 只看该作者
不明白“恢复现场(手动)”

使用特权

评论回复
11
xuyaqi| | 2010-12-25 20:24 | 只看该作者
另外不明白改变count变量的值为什么要通过寄存器来进行。

使用特权

评论回复
12
coreduo| | 2010-12-25 20:52 | 只看该作者
这是多线程的基本操作,看来这个论坛做软件 的很少.
其实这个问题很好解决就是加mutex或者sem保护,所有操作系统都可以实现,中断安全.
mutex本身是利用原子操作实现的.

使用特权

评论回复
13
kolo| | 2010-12-25 20:55 | 只看该作者
操作系统也有这个问题,叫互斥信号量,比较复杂。
你不能一下就解决,需要换思路

使用特权

评论回复
14
okay007|  楼主 | 2010-12-25 22:49 | 只看该作者
不明白“恢复现场(手动)”
xuyaqi 发表于 2010-12-25 20:02

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

11楼,count变量为什么用寄存器,这个不是问题吧?CPU中一定要寄存器的!

使用特权

评论回复
15
okay007|  楼主 | 2010-12-25 22:51 | 只看该作者
这是多线程的基本操作,看来这个论坛做软件 的很少.
其实这个问题很好解决就是加mutex或者sem保护,所有操作系统都可以实现,中断安全.
mutex本身是利用原子操作实现的. ...
coreduo 发表于 2010-12-25 20:52

windows程序中,我都用线程锁完成。
只是单片机中无法解决。

使用特权

评论回复
16
xuyaqi| | 2010-12-25 23:31 | 只看该作者
“"恢复现场"用汇编都要程序员自己编程的“,不需要自己编程如51汇编一条语句“POP DATA”。
“count变量为什么用寄存器,这个不是问题吧?CPU中一定要寄存器的!”变量可以直接放在DATA,IDATA,XDATA存贮器,都不是寄存器。

使用特权

评论回复
17
原野之狼| | 2010-12-25 23:59 | 只看该作者
正如ayb_ice所说,这种问题确实是个基本问题。
可以认为单片机的程序前台和后台就是两个线程,所以你说的在WINDOWS编程中会遇到的问题在这里也会遇得到的。
解决的方法有很多:
1、如果变量是作为标志位使用,那么尽量使用char类型,这样访问的时候就具有原子操作了。
2、在访问之前禁止中断位。
3、如果所使用的变量不具备原子操作的属性,那么在前台程序中可以多次读取该变量然后在进行比较以判断操作的安全性。

使用特权

评论回复
18
okay007|  楼主 | 2010-12-26 08:20 | 只看该作者
本帖最后由 okay007 于 2010-12-26 08:42 编辑
正如ayb_ice所说,这种问题确实是个基本问题。
可以认为单片机的程序前台和后台就是两个线程,所以你说的在WINDOWS编程中会遇到的问题在这里也会遇得到的。
解决的方法有很多:
1、如果变量是作为标志位使用,那么尽 ...
原野之狼 发表于 2010-12-25 23:59

首先谢谢你的回答!虚心请教!
1、我不明白char型变量就是原子操作吗?怎么我实验的代码不是呢?。
2、这样应该可以,没有不关中断的类似windows多线程编程的方法吗?
3、你说的前台程序是指主程序吗?
下面是我实验的一段AVR代码,人工仿真确实会出现上面分析的问题,变量也是char型的。能否再详细些?谢谢!

使用特权

评论回复
19
lczsx2000| | 2010-12-26 08:35 | 只看该作者
单片机你就关中断,然后再count+=1;再开中断不就解决了

使用特权

评论回复
20
coreduo| | 2010-12-26 21:09 | 只看该作者
单片机你就关中断,然后再count+=1;再开中断不就解决了
lczsx2000 发表于 2010-12-26 08:35

无操作系统编程的正解.

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

4

主题

31

帖子

2

粉丝