打印

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

[复制链接]
楼主: okay007
手机看帖
扫描二维码
随时随地手机跟帖
21
原野之狼| | 2010-12-27 00:28 | 只看该作者 回帖奖励 |倒序浏览
LZ的好学态度与谨慎作风值得学习,赞一个先~
1、我不明白char型变量就是原子操作吗?怎么我实验的代码不是呢?。
并不是说char型变量就是原子操作,我之前所说的第一条讲到的是作为标志位来操作,这样的操作在汇编指令上是具有原子性的。至于LZ的例子里提到的++count操作并不具有原子操作,你的例子已经阐述得很清楚了,或许别的平台(比如32位)类似于++count操作是具有原子操作的,这个你自己核实,我并不能确定,因为平时很少使用汇编。
2、这样应该可以,没有不关中断的类似windows多线程编程的方法吗?
windows的多线程做法其底层也不过是一些汇编代码嘛,本质并没有改变,所以不要被它震慑住了或是觉得有多神奇,其多线程的操作是属于高层的做法了,在MCU下你自己也可以实现的,并不是太难,详细地可以参阅一下开源OS的信号量机制是如何实现的。
3、你说的前台程序是指主程序吗?
前台程序就是由main函数开始的运行分支,后台程序指中断程序。

使用特权

评论回复
22
okay007|  楼主 | 2010-12-27 11:04 | 只看该作者
本帖最后由 okay007 于 2010-12-27 18:52 编辑
LZ的好学态度与谨慎作风值得学习,赞一个先~
1、我不明白char型变量就是原子操作吗?怎么我实验的代码不是呢?。
并不是说char型变量就是原子操作,我之前所说的第一条讲到的是作为标志位来操作,这样的操作在汇编指 ...
原野之狼 发表于 2010-12-27 00:28

非常感谢你的指导,使我有了比较深的认识!
要搞明白的原因?主要是现在做了一个小控制项目,运行几天可能就会出现问题,查不出原因,按照你的指点修改了单片机的程序,现正在测试,还没有发现问题。
我现在有不多的几个全局变量作为标志用,现在定义成寄存器变量,反汇编看已经是原子操作了,最后再一次感谢!

使用特权

评论回复
23
刘前辈| | 2010-12-27 17:59 | 只看该作者
本帖最后由 刘前辈 于 2010-12-27 18:01 编辑

LZ举的是操作系统教材书上写的典型的mutex()例子,连6、7 数值都和教材一样。这样的问题在单片机中一样存在。
现在的解决关键是:单片机超循环程序中不用关中断能不能写出个原子操作mutex( )?

关中断的方式实在太初级了,所有人都能做到的。在多CPU并行系统中,关中断根本无效,只能采用公共互斥锁保护临界区的方法。所以,谁能写出个简单的mutex()函数,才是大师。

使用特权

评论回复
24
okay007|  楼主 | 2010-12-27 18:59 | 只看该作者
楼上朋友高见!期待给个在无操作系统的单片机C程序中不用关中断的方法!
不过这个例子我不是在你说的书上看的,是在NI网站的labwindows白皮书中关于labwindows多线程编程中看的,可能是经典例子,都在引用吧!

使用特权

评论回复
25
李冬发| | 2010-12-27 19:51 | 只看该作者
除非硬件支持,否则仅关中断一条路。
一般的MCU里,char是原子操作。

使用特权

评论回复
26
okay007|  楼主 | 2010-12-27 20:35 | 只看该作者
本帖最后由 okay007 于 2010-12-27 20:53 编辑

TO:25楼
为什么我发现,MCU中 char一般不是原子操作?通过观察反汇编代码,除非是局部变量或定义成寄存器变量。

使用特权

评论回复
27
刘前辈| | 2010-12-28 09:27 | 只看该作者

谁说仅关中断一条路?A51就可以实现mutex

本帖最后由 刘前辈 于 2010-12-28 09:32 编辑
from  25楼:
             除非硬件支持,否则仅关中断一条路。



嘻嘻,25楼高手,我就用纯软件做mutex( ),就用标准8051,没有硬件支持;

所有的人向左,我必向右。

使用特权

评论回复
28
chunk| | 2010-12-28 10:26 | 只看该作者
到GOOGLE查"线程局部存储"

使用特权

评论回复
29
okay007|  楼主 | 2010-12-28 11:07 | 只看该作者
本帖最后由 okay007 于 2010-12-28 12:28 编辑

27# 刘前辈
你看反汇编代码了吗?底层没有调用关闭中断指令和恢复中断?
最好给个有说服力的证据!
刚刚仔细看过IAR内部实现“共享变量”的方法,其实底层也是采用关中断和恢复中断的方法。
支持一下“25楼”

使用特权

评论回复
30
刘前辈| | 2010-12-28 17:11 | 只看该作者
本帖最后由 刘前辈 于 2010-12-28 17:18 编辑

提示一下,mutex 实际上是一把锁,它的关锁动作必须是原子性指令,完成2个动作:测试,执行;——就像商场试衣间,即:(测试)如果已上锁,等待或离开;否则执行操作:

就好像(大意如下)
lock ;     // mutex( );
count++ ;
unlock ;

      任何CPU 都有 “测试-执行 ”单指令原子操作吧。C51都有,
_testbit ( bit )_ ,A51更直接;别说86了。

使用特权

评论回复
31
okay007|  楼主 | 2010-12-28 17:25 | 只看该作者
还是我问你的,你看过反汇编了吗?
怎么越来越觉得你的方法底层100%是通过关中断实现的了呢?哈哈!
你的mutex( );函数只是C做的封装,你最好看一下编译后的反汇编代码,我可刚看完IAR的!

使用特权

评论回复
32
aaa2742| | 2010-12-28 17:32 | 只看该作者
:@

使用特权

评论回复
33
刘前辈| | 2010-12-29 09:08 | 只看该作者
本帖最后由 刘前辈 于 2010-12-29 09:17 编辑

mutex()绝对没有关中断,这里重要的是加了一把互斥锁

上面说过,LZ的问题可以用商场的试衣间比喻(教材上是用洗手间作比喻的,咱文明点就改用试衣间);LZ是没有锁的试衣间,所以前后台都可以没有障碍地进入临界区—试衣间,造成混乱。关中断不过是强制停止前台的激活运行,—— 可以想象,如果后台占用试衣间期间发生中断,关中断会造成什么严重影响,——所以下策,教材、教授不会这么讲课的。

mutex( )是给试衣间加了一把互斥锁,所有中断服务仍可运行,——欲使用被后台占用试衣间的只好等待;——这里加入了有序使用试衣间的规则——机制。所以,mutex( )函数不是原子性的,它不必关中断,像普通函数一样,执行期间可以被前台程序中断,返回;——而关键的是,mutex( )函数里面的关锁指令必须是原子性的!

再次提示:请看看 _testbit(bit)_ 是不是原子性指令?

汇编指令:JBC   锁,执行 ;    是不是原子指令?

什么地方关了中断?

使用特权

评论回复
34
okay007|  楼主 | 2010-12-29 11:41 | 只看该作者
本帖最后由 okay007 于 2010-12-29 11:44 编辑

JBC是原子指令吧。但是真的不知道你的如下形式的指令:
lock ;     // mutex( );
count++ ;
unlock ;
在无操作系统情况下,怎样保证在执行count++时不被中断打断。因为你的lock没有关中断,并且中断也不会关心JBC指令吧?
虚心请教!谢谢!

可能在有操作系统情况下JBC可以保护变量,这个不讨论!

使用特权

评论回复
35
刘前辈| | 2010-12-29 13:03 | 只看该作者

我没涉及操作系统,纯粹的超循环代码。

本帖最后由 刘前辈 于 2010-12-29 13:25 编辑

看来我要花时间写一段实际代码了:我以为讲得够清楚了,是不是一定要写出实际代码,伪代码看不懂?再来一段更清楚的伪代码:

全局变量: bit 锁=1; boolean 锁开锁状态UNLOOK。

;后台进入临界区计算count+1 程序如下:(  下面程序可随机中断。 )
……
JBC  锁,临界区L001  ;原子指令!先测试锁状态,if 锁打开(UNLOCK ),
                            ; 进入临界区(试衣间)L001,并关锁LOCK ,——bit锁=0=LOCK。
return    ;   else if  锁状态关闭LOCK,有人在试衣间,不必计算count 。

临界区L001:
count++;
SETB  锁 ;
计算完毕,开锁UNLOCK;退出临界区,让出试衣间给他人用。
return ;


前台程序与上面后台程序完全一样。—— 没有开/ 关中断语句。

还不清楚?那就贴一个实用 C51 mutex()。

/

使用特权

评论回复
36
okay007|  楼主 | 2010-12-29 13:29 | 只看该作者
你说的没有问题,非常正确。
不过我感觉你说的好像根本不是我问的问题!
不是我没理解你的意思,就是你没理解我的意思(包括其他几位朋友的意思)。

使用特权

评论回复
37
刘前辈| | 2010-12-29 13:44 | 只看该作者
都是多线程共享资源的保护问题。
OS环境下,关中断实际是关调度,——关闭切换程序;显然不好,优先级进程(无关共享资源的I/O 中断 )也被关掉了。

所以,使用互斥锁(内核对象)保护共享资源的访问,同时又不影响中断源的实时响应。

超循环意思一样。

使用特权

评论回复
38
okay007|  楼主 | 2010-12-29 13:57 | 只看该作者
本帖最后由 okay007 于 2010-12-29 15:50 编辑

看来你说的不是我问的!
我虽然用多线程引出问题,但是根本不是问的多线程,你可能没有细心看问题帖,所以说你没理解我的意思(包括其他几位朋友的意思),并且我再三说无OS情况。
多线程用“互斥锁”肯定是没有问题的,关中断肯定是不好的。
不过还是要谢谢你!

使用特权

评论回复
39
刘前辈| | 2010-12-29 19:30 | 只看该作者

还是没看懂。

本帖最后由 刘前辈 于 2010-12-29 19:58 编辑

35楼也没写什么多线程或者进程/任务,完全是裸奔。写的是A51或者C51程序,和OS 一点不搭界。主要是用LOCK锁解决了LZ   7# 下面的问题:        


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



C51的内联函数 _testbit (bit)_ 是普通函数,多用途的,不是专用互斥锁。

       LZ可以试试采用了35楼的锁机制之后,count 结果还会混乱么?如果正确,那就是有效机制,是前后台共享资源互斥访问(临界区保护)解决方案,和多线程无关。

         LZ 说的如果不是上面红笔引用,那么到底想表达什么?

使用特权

评论回复
40
刘前辈| | 2010-12-29 20:07 | 只看该作者
我帮LZ叙述一下:35楼的缺点在于“如果后台锁闭合时发生中断,则中断的count++被禁止,并且不能等待重复执行。也就是丢掉了一次count++运算。”

欲使前后台count++都有效,是这个意思?

使用特权

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

本版积分规则