独闷闷网

 找回密码
 立即注册
搜索
查看: 3732|回复: 0
收起左侧

[原创] 为什么要用开关中断,原子锁或互斥量来保护多线程共享的全局变量?已解答。

[复制链接]
发表于 2014-11-5 19:37:56 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
本帖最后由 jianhong_wu 于 2015-1-27 15:14 编辑

waphaoyun:
感觉原子锁就是对变量的保护,使变量不能被同时赋值。51单片机是单核的,也就是说 无论定时器中断还是串口中断中 ,都不会出现对同一个资源同时访问的情况,而是分时间片分别访问同一个变量,从而感觉原子锁是没有必要的,  希望鸿哥可以帮忙简要回答一下,谢谢鸿哥!

鸿哥-深圳:
在前面一些章节中,我提到为了防止中断函数把某些共享数据破坏,在主函数中更改某个数据变量时,应该先关闭中断,修改完后再打开中断;我也提到了网友“红金龙吸味”关于原子锁的建议。经过这段时间的思考和总结,我发现不管是关中断开中断,还是原子锁,其实本质上都是程序在多进程中临界点的数据处理,原子锁有个专用名词叫互斥量,而我引以为豪的状态机程序框架,主函数的switch语句,外加一个定时中断,本质上就是2个独立进程在不断切换并行运行。为什么要保护多线程共享的全局变量?因为,多个线程同时访问同一个全局变量,如果都是读取操作,则不会出现问题。如果一个线程负责改变此变量的值,而其他线程负责同时读取变量内容,则不能保证读取到的数据是经过写线程修改后的。如果是1个字节char变量没关系,如果是int等类型的2个字节以上的数据就有必要考虑一下。因为char是一个字节,在数据改变的时候,一条指令就可以更改完毕.而int是2个字节,更改数据的时候至少需要2条指令以上,所以我怕在刚执行一条指令的时候,还没来得及执行完第二条指令,也就是int数据还没更改完时出现定时中断,而恰好在定时中断里有发生了更改次变量的情况。

糕富帅-深圳:
有点高深。

鸿哥-深圳:
我打算在新开的技术贴中简化原子锁,但是能起到同样的作用。原子锁到底是不是真的那么有作用,其实还是有点争议的,但是鸿哥还是宁愿信其有吧,我为这个问题曾经纠结过很久的,因为我以前不用原子锁。

糕富帅-深圳:
因为变化细微,好难去理解到底有没有作用。貌似在多线程上还是有用的,对于51这种单片机,单步执行的,我觉得好像没用。

伟-肇庆:
不能这么说,比如你这主程序中,对一链表操作的时候,突然来了中断,也对链表进行操作,这是很有可能出现致命性错误的,原子所是有他存在的意义的。在UCOS,不叫原子锁,叫临界区。访问多任务共享的变量,都要严格进入临界区去处理。

糕富帅-深圳:
如果是51单片机,不跑系统。原子锁也有存在的意义?


伟-肇庆:
中断呀。也有呀。在中断程序中,主程序访问期间,来了个中断。比如,你在主程序中有一个指针,通过该指针访问一块内存,不加原子所,在中断操作中,改变了该指针的指向,这是中断返回。指针就不是之前的指针了。

糕富帅-深圳:
嗯嗯,这个理解。

伟-肇庆:
加锁,或者进入临界区操作,简单就是一句话,我当前访问期间,不希望别人进入修改,就得有加锁的思想,上锁,其他线程,任务,中断都不得访问,除非我解锁或退出临界区,保证当前操作的完整性。

鸿哥-深圳:
我当时是听取了网上红人“红金龙吸味”的建议,当时我也相当纠结,纠结了两天,最后还是决定听取他的意见。

尚哥-深圳:
我写汇编的时候有发现过这样的问题,还出过事,一堆人在帮我查,最后发现是,变量在主循环中把数据送给了ACC,这时中断到了,在中断里面改变了这个变量,当回到主循环时,又继续从ACC里面取数据,就错了,后来就用关中断解决的。我觉得 C 语言应该有能解决这个问题,我一直都是用volatile来做的,暂时还没发现问题。

waphaoyun:
我好像明白了:不是同时访问的问题,是时间片分配的问题,可能会出现一个赋值语句进行一半的时候 就把时间片分给了另一个语句的情况,从而造成错误,原子锁是为了保证 变量能够一次正确赋值的,应该是这回事!初学者,应该是我理解的不对,大家见笑了。。。

Kelvin--江门:
1.png
2.jpg
3.jpg
4.png

鸿哥-深圳:
volatile关键字有什么特点?跟我们科普一下。

尚哥-深圳:
我在21IC论坛看到的网友交流,现在复制过来如下:
volatile关键字告诉编译器,这个变量是易变的,不要进行优化。一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。比如:

变量不加volatile的话,默认是优化的,如下:
int a = 100;
int b = a;
int c = a;
在执行程中,如果第二条语句和第三条语句之间变量a未成用作左值,那么即使变量被某些操作(如中断)改变成200了,执行完后变量c还是等于100。
如果加了volatile的话,在执行int c = a;语句的时候,会重新从内存取出a的值(此时为200),所以c会等于200。


鸿哥-深圳:
看了你上述关于volatile的描述,我觉得volatile仅仅是跟编译器优化有关系,但是跟上面提到的多线程保护共享数据没什么关系。所以我觉得针对这个问题volatile可能没什么作用。



乐于分享,勇于质疑!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|独闷闷网 ( 粤ICP备12007667号-2 )

GMT+8, 2021-6-14 01:22 , Processed in 0.139190 second(s), 21 queries .

快速回复 返回顶部 返回列表