英文好的,可跳过,直接打开底部的“参考“链接。
代码变序--reordering of memory operations
大概4年前,阅读了这篇文章后http://www.albahari.com/threading/,我就自我满足,多线程编程不过就是用那些工具而已。
今天,读了一篇文章后,http://msdn.microsoft.com/en-us/magazine/jj863136.aspx,才发现C#代码是可以变序的(上面的文章也提到了,忘得一干二净)。
举例,你写出如下的代码
- void Init() {
- _data = 42;
- _initialized = true;
- }
JIL运行时的代码却可以像这样(不是IL代码哦,IL编译出代码与源代码是一致的)
- void Init() {
- _initialized = true;
- _data = 42;
- }
这个坑爹的JIL优化,如果不注意,可能就不会抓住bug所在。底部有我写的再现方法。先别运行程序,试试猜猜结果有几种可能。
总结:浮躁+记忆力差是很致命的,必须要找适合自己的工作方式。深入理论上理解+上手验证,这样才算消化,也不容易忘。
不重复造轮子,更不能重复学习。
参考:
http://msdn.microsoft.com/en-us/magazine/jj863136.aspx
http://msdn.microsoft.com/en-us/magazine/jj883956.aspx
class Program { static void Main(string[] args) { DataInit di = new DataInit(); new Thread(() => { di.Init(); }) { IsBackground = true }.Start(); new Thread(() => { di.Print(); }) { IsBackground = true }.Start(); Console.WriteLine("Running... Press enter to quit"); Console.ReadLine(); } } public class DataInit { private int _data = 0; private bool _initialized = false; //准备些无用的field private char _c = '0'; private int _data1 = 0; private int _data2 = 0; private int _data3 = 0; private int _data4 = 0; public void Init() { _data = 42; // Write 1 _initialized = true; // Write 2 //下面的field赋值是用来触发JIL 优化的,如何触发的原理,我不知道:(。 ///*try屏蔽下面的代码,结果很可能就是42了 _c = '0'; _data1 = 0; _data = 0; _data2 = 0; _data3 = 0; _data4 = 0; } public void Print() { Console.WriteLine(_data); Console.WriteLine(_initialized); if (_initialized) { Console.WriteLine(_data); //should 42,有时候确是0 } else { Console.WriteLine("Not initialized"); } } }