近来在学习Eugene Agafonov编写的《C#多线程编程实战》(译),做些笔记也顺便分享一下^-^
using System; using System.Threading; namespace SpinWait_Test { class Program { static void Main(string[] args) { var t1 = new Thread(UserModeWait); var t2 = new Thread(HybridSpinWait); Console.WriteLine("Running user mode waiting"); t1.Start(); Thread.Sleep(20); _isCompleted = true; Thread.Sleep(TimeSpan.FromSeconds(1)); _isCompleted = false; Console.WriteLine("Running bybrid SpinWait construct waiting"); t2.Start(); Thread.Sleep(5); _isCompleted = true; Console.ReadKey(); } static volatile bool _isCompleted = false; static void UserModeWait() { while (!_isCompleted) { Console.Write("."); } Console.WriteLine(); Console.WriteLine("Waiting is complete"); } static void HybridSpinWait() { var w = new SpinWait(); while (!_isCompleted) { w.SpinOnce(); Console.WriteLine(w.NextSpinWillYield); } Console.WriteLine("Waiting is complete"); } } }
程序运行结果如下
当主程序启动时,定义了一个线程,将执行一个无止境的循环,直到20毫秒后主线程设置_isCompleted变量为true。我们可以试验运行该周期为20~30秒,通过Windows任务管理器测量CPU的负载情况。取决于CPU内核数量,任务管理器将显示一个显著的处理时间。
我们使用volatile关键字来声明_isCompleted静态字段。Volatile关键字指出一个字段可能会被同时执行的多个线程修改。声明为volatile的字段不会被编译器和处理器优化为只能被单个线程访问。这确保了该字段总是最新的值。
然后我们使用了SpinWait版本,用于在每个迭代打印一个特殊标志位来显示线程是否切换为阻塞状态。运行该线程5毫秒来查看结果。刚开始,SpinWait尝试使用用户模式,在9个迭代后,开始切换线程为阻塞状态。如果尝试测量该版本的CPU负载,在Windows任务管理器将不会看到任何CPU的使用。