多线程安全问题,到底有没有可能同时读写同一块内存? 专家来吧。(100分)

  • 主题发起人 xiaohongna
  • 开始时间
X

xiaohongna

Unregistered / Unconfirmed
GUEST, unregistred user!
首先我提出这个问题是在TThread类里面
procedure TThread.Terminate;
begin
FTerminated := True;
end;
也就是说这个方法直接写了一个变量的值。 由于我在写得时候也用了同样的方法,就是对一个变量的读或者写不考虑线程安全问题,仅仅局限于一次读或者写操作。
但是现在问题出来了,这中用法到底安全不安全啊?也就是到底有没有可能同时对一个8位 或者 32位的内存进行读写两个操作那?
我查了一些资料,只有只言片语说了在Win上面对一个8位的读或者写都是原子性的。但并不是说就是线程安全的阿? 我还询问了一个多年经验的人,他说同时读写两个操作同一块内存可能发生,他还说TThread这种写法就是有Bug。
但还有一些人说硬件上面这种情况不会发生。我也不清楚硬件。 但是通过设置一个变量的值来在多个线程之间使用却是经常用的,今天突然想不明白了,越想越糊涂!
 
从硬件层面上说 对一个内存地址的8位读写都是原子性的
例如你要向0x5100写0x1a 写完之后这个地址就是你写的值了
对于线程来说 关键的问题不是在于读写是否成功 而是是否脏读或者脏写
例如你的线程代码是这样一个逻辑
a:=0;
sleep(10);
a:=a+1;
sleep(10)
if a=1 then
a = 0
这里a是一个两个线程都能访问的全局变量
那么问题就来了 如果你没有同步或者使用临界区
if a=1 then
这句你一定能读到a=1么
 
to ball_cao
我觉得你说的和我提的问题没有一点关系,既然一个读和一个写是原子性的,那么你下面写的语句明显不是原子性的,用同步就是为了把这不是原子性的事物变成原子性的。
现在问题是在原子性的基础上面, 我在一个线程里面设置一个值,比如Fterimnated 然后同时可能其他的线程就在读这个值,你看好这两个事件都是原子性的。 一个是唯一的一次读,一个是唯一地一次写,都是原子性的。 现在我问的是到底会不会同时发生!
 
同时发生的可能性肯定有的,只是看你这个读写操作的时间长短,如果读写的时候越短。那么同时发生的概率越低,现在cpu的计算速度越来越快,可以说对一个地址指针的读写操作基本上可以忽略,但忽略并不表示没有 。
其实ball_cao说的没错,线程同步也有一部分是为了防止数据脏读,因为各个线程的操作是无法控制的,所以必须同步。所谓脏读就是说,你刚写的东西跟你读取出来的东西不一样,这时候就即使存在什么原子性,那也是有问题的。
然后TThread.Terminate的方法应该是外部调用线程执行的吧,其实TThread执行时内并没有对FTerminated进行赋值操作,只是在判断FTerminatedl,看外部线程是否执行了结束操作。
 
to xiaohongna
注意我谈的命题条件 是读的多个线程共同访问的对象
您的题目里写的变量是线程类自己的私有变量,其他线程是不能直接访问的
但是并不代表其他线程不能访问 你可以做一个包装将这个变量发布出来
所以你还是有可能会面对我说的脏读或脏写的问题
什么是原子性?假设我们说操作系统级的原子性是一个byte的读写,这种原子性就是你要表述的业务的原子性么?
你的题目中提到的多线程编程中需要解决的原子性问题,就是系统原子性小于业务逻辑原子性的问题。
msn:ball_cao@hotmail.com
 
单核CPU的原子性读写是不可能同时发生的。
多核CPU对同一块内存的原子性读写也应该是不可能发生的,有内存总线的限制。
至于FTerminated := True;这个不用担心吧,不同的线程实例中,这个FTerminated根本就是不同的变量,无所谓同时读写的。
 
原语这个概念的基础就是不可被打断。在内存硬件本身是独占、不支持多CPU共享总线同时读写的情况下,这个不能被打断的原语就是独占内存的,所以原语与原语之间不可能同时发生。
 
貌似从硬件的角度来看确实是不可能发生的。
CPU读写内存,无论是几个CPU的机子,在读内存前,首先要锁定地址总线,给出本次要读写的内存地址,同一时刻,地址总线不可能同时被两个或者两个以上线程所锁定,这相当于独木桥一样,只能等前面的去了回来了,再下一个去取。
所以从总线占用的角度去考虑,感觉是不太可能会发生上述情况。
 
to jacket84
判断Terminated 至少是一次读操作
to Passion
不同的线程中这个变量的确是不同的,但那个方法可以由其他的线程同时调用,也就是同时写了,当然本线程内也许就在不停的判断Fterminated
to levi
现在大多数人都说这种情况不会发生,我觉得从硬件的角度上说是这样的。 现在我就按这种理论写出来的程序也没有问题。
其实反过来想,假设能发生,本来是flase 一个再度 一个同时也写True,那么到底是True还是flase那? 所以内存应该不会容许同时发生的。 另外内存一个时钟周期不应该存在读和写两种情况的,所以也不会同时发生。
 
多人接受答案了。
 
顶部