首页
社区
课程
招聘
[求助]win32多线程程序设计
发表于: 2009-2-12 15:57 3147

[求助]win32多线程程序设计

2009-2-12 15:57
3147
很多问题向诸君求教.望赐教.谢谢
具体下载地址:win32多线程程序设计
自解是指我认为是正确的解答,请诸君验证之;
无解是指我不知道解答,请诸君答之
问题:
[1]37页的单链表例程在添加flag处理(40页)后,此处我理解来flag==1时为表示其他线程在使用链表,而flag==0则表示无线程在使用链表.书中说"如果context switch发生于#8和#9两行之间,另一个线程即可进入该函数--即使该函数设立了标记..."不解.
     (1)如若在#8和#9行发生context switch可能失败?
     自解:指另一个线程B刚好释放控制(即指完成链表操作之后flag被设定为0),此时发生context-switch则另一个线程C(不同于B且不同于本线程A)的线程可能会得到控制权.但是我以为这不是问题啊,因为线程C中应该也是使用while(flag!=0) ;这种语句,因此在flag被设定为0时,该线程应该也会通知到,进而运行.此时惟一要看的就是操作系统分配time slice到那一个线程罢了.
     (2)如果context switch发生在#20或#21行之后,则函数可行失败?
     有解:为什么讲#20或#21行之后?是否是讲刚好执行完#20或#21行之后.
     无解:即使context switch发生于该处,flag的值没有为0,则其他调用该函数的线程不可能访问到链表,则不会出现前例的memory leak的情况.so why?

[培训]科锐逆向工程师培训第53期2025年7月8日开班!

收藏
免费 0
支持
分享
最新回复 (7)
雪    币: 2110
活跃值: (21)
能力值: (RANK:260 )
在线值:
发帖
回帖
粉丝
2
多线程的同步和死锁问题,关键是要完全清楚,究竟哪些操作是原子完成的,哪些操作不能够以原子方式完成。

从这个角度去思考。

我没有看你给出的链接的内容,所以暂无法针对你具体的问题来回答,你先自己再思考一下。

我一会有时间会看一下你的问题的。
2009-2-12 21:17
0
雪    币: 83
活跃值: (11)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
3
嗯.有时间的话.请具体看一下.我具体已经想了,但是还是不理解.期待诸君点拨.
2009-2-12 21:50
0
雪    币: 2110
活跃值: (21)
能力值: (RANK:260 )
在线值:
发帖
回帖
粉丝
4
文件太大,链接太慢。还在线就直接贴代码出来吧。

再过一会我要睡了,今天有些累了,没看到你代码,就明天再看吧。
2009-2-12 22:35
0
雪    币: 83
活跃值: (11)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
5
嗯.如果是在windows下可以使用迅雷.速度较快.
本书是《win32多线程程序设计》候捷译.
2009-2-12 22:53
0
雪    币: 2110
活跃值: (21)
能力值: (RANK:260 )
在线值:
发帖
回帖
粉丝
6
大体看了一下,基本明白你的疑惑了。

还是我一开始说的,你必须明白究竟什么操作是原子的,什么操作不能够以原子方式完成。

问题1:

这个问题书中描述确实有点含糊。实际上这里的问题不是#8与#9,而是#8、#9与#14、#15、#16这个操作无法按原子方式完成。前两行对应C源代码中的while(flag);后三行对应C源代码中的flag=1;

其实,只有这条指令以原子方式执行,才可以在多线程之间实现加锁。也就是所谓的以原子的方式实现的“测试并设置”指令。

简单地说,根本原因在于,程序在#8判断flag是否为0,而在#16才设置flag为1。如果flag为0,线程A在#8执行比较指令,认为flag为0,CPU的状态寄存器eflags已经被设置为ZF=1,那么就会获得控制权,将继续执行下面的操作(而不是执行循环等待)。但是,如果线程还没有执行#16的mov flag,1这条指令,就发生了线程切换,线程B进入这个函数时,会看到flag仍为0(而它应该为1,因为线程A已经开始执行下面的操作了),于是也会获得控制权。

于是现竞态出现了:线程A、B同时进入了“临界区”。结果又回到了37页讲的没有加锁的结果了。

而问题2中所说的#20和#21,就是在前面这种情况发生的基础上所发生的。

你所认为的另一个线程会在flag=1的情况下自旋,实际上是没有对问题1完全理解。如果理解了问题1,就会知道,当线程A在执行到#20、#21时,线程B对“flag是否为0”的测试有可能是不正确的。

所以,在多线程中,要实现“锁”的机制,最底层的硬件必须提供一个总线互锁的(从而保证可以原子完成的)“测试并设置一个内存变量”的机制,IA32结构中,就是BTS指令,在ARM,有一条swap指令,用来实现并行处理的上锁机制。

“测试并设置”,为什么必须要总线互锁才能原子地完成呢?因为这条指令实现是由两个动作组成:“测试”要发起一次总线的操作,来读取内存变量的值;“设置”要发起一次总线的操作,来设置内存变量的值。而普通的存储器访问指令,只有一次总线操作。

再回头看一下原来的C程序,就可以理解了:测试用了一条语句(while(flag);),设置用了一条语句(flag=1;),而这两个操作不能以原子方式完成。就这么个原理。
2009-2-13 08:41
0
雪    币: 83
活跃值: (11)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
7
非常感谢书大的指点.
2009-2-13 10:46
0
雪    币: 83
活跃值: (11)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
8
我居然没能想到那个#8,#9之后context switch.是被书误导所致.
也就说该书实际上是讲错了.实际本问题应该是#9-->#16之间如果发生context switch则其他线程亦可进入该函数.而后边的所谓的#20,#21之类其实也就是指在#9-->#16之间发生context switch之后(有一个线程B操作了一半的链表),而又切换到另一线程A(进行链表操作)则会发生之前的memory leak问题.
---
thx.
2009-2-13 10:49
0
游客
登录 | 注册 方可回帖
返回