假设我们有一个多线程的C程序(pthreads),并且各个线程的(非同步)共享变量访问不会被编译器重新排序。 x86 CPU是否尊重共享变量访问的顺序(在单个线程中),还是有可能重新排序某些内存访问?多线程和无序执行
多线程和无序执行
回答
非同步共享变量访问是危险的,并且乱序是其原因之一。
x86保持写入顺序(在一个线程内),但不能读取。
如果您认为订单仍然存在,这可能会让您陷入困境。例如:
线程A写入x然后写入y。假设编译器没有对它重新排序,CPU不会重新排序(x86不会,其他可能)。
线程B读取y,然后读取x。你可能会认为,如果它具有y的新价值,那么你肯定也会得到x的新价值。
并非如此。 CPU可能会对线程B的读取进行重新排序,所以y会被更早读取。
编辑:为“单向的男人”中指出,在这种情况下,X86保证排序(但不是所有的处理器!)。
我引用英特尔软件开发人员手册:
写入由单个处理器中所有 处理器相同的顺序观察。
这对于多处理器写入来说并不正确 - 它们看起来可能被不同的处理器按不同的顺序排列。
但是,我强烈建议不要依赖它,并使用适当的同步来代替。
同步原语是通过原子操作和/或障碍来实现的,它们保证您的安全。
您是否可以用另一次读取重新排序读取? “线程B读取y然后读取x,您可能会认为如果它获得了y的新值,那么您肯定也会得到x的新值。”我不认为这是真实的根据英特尔手册:“读取不会与其他读取重新排序”。阅读可以重新排序与旧的写作虽然。 – 2013-09-09 20:33:32
@ManofOneWay,你说得对。该手册还指出“所有处理器以相同顺序观察单个处理器写入”。我认为,我的底线是正确的 - 根据这些细节编写正确的无同步代码几乎是不可能的。 – ugoren 2013-09-10 08:51:58
x86在加载和旧存储时不保证排序,因此如果存在A然后是加载B,并且它们引用不同的存储位置,则加载B可能会在A之前移动。因此,隔离仍然存在在某些情况下需要。 – 2013-09-10 09:02:07
由于存储缓冲区的存在,一些重新排序是可能的。见例如https://www.cl.cam.ac.uk/~pes20/weakmemory/cacm.pdf
但是,重排序只能看到几个线程,在单个线程中,该线程的所有访问都按顺序发生。
- 1. 执行多线程程序
- 2. 多次执行线程和运行程序的区别
- 3. 并行执行和终止多线程
- 4. 了解多线程和执行过程
- 5. 执行多线程进程
- 6. 多线程代码 - 力执行顺序
- 7. 多线程与乱序执行的
- 8. 多线程和委托执行
- 9. 线程池执行程序
- 10. 暂停/执行多线程程序中的一个线程(C#)
- 11. 强制Eclipse执行多线程Java程序单线程
- 12. 多线程程序只执行最后创建的线程?
- 13. 如何执行多线程应用程序作为线程?
- 14. 多线程执行写入?
- 15. 多线程执行模式
- 16. 多线程TestNG DataProvider执行
- 17. 执行多个线程
- 18. 多线程同步执行
- 19. 在多线程程序中执行另一个程序
- 20. 正确使用JavaFX任务执行多线程和线程池
- 21. CUDA线程执行顺序
- 22. 线程执行时序
- 23. 已排序执行线程
- 24. boost ::线程执行顺序
- 25. 执行线程的顺序
- 26. 线程执行序列
- 27. 线程执行顺序
- 28. 执行程序优于多线程应用程序中的线程
- 29. Java:另一个多线程执行程序中的单线程子执行程序
- 30. 为什么我的多线程程序按顺序执行?
无序/推测调度执行只存在于微代码级别(后端)。 (请通知@我,因为我没有手动检查答案) – user2284570 2013-11-23 01:47:22