杭州大型网站建设,网页设计实验报告步骤分析怎么写,深圳网站设计|优选灵点网络,有哪些做任务网站用多个线程编程并不容易。在启动访问相同数据的多个线程时#xff0c;会间歇性地遇到难以发现的问题。如果使用任务、并行 LINQ 或 Parallel 类#xff0c;也会遇到这些问题。为了避免这些问题#xff0c;必须特别注意同步问题和多个线程可能发生的其他问题。下面探讨与线程… 用多个线程编程并不容易。在启动访问相同数据的多个线程时会间歇性地遇到难以发现的问题。如果使用任务、并行 LINQ 或 Parallel 类也会遇到这些问题。为了避免这些问题必须特别注意同步问题和多个线程可能发生的其他问题。下面探讨与线程相关的问题争用条件。ThreadingIssues示例的代码使用了如下名称空间: System.Diagnostics System.ThreadingSystem.Threading.Tasks static System.Console可以使用命令行参数启动 ThreadingIssues示例应用程序来模拟争用条件。如果两个或多个线程访问相同的对象并且对共享状态的访问没有同步就会出现争用条件。为了说明争用条件下面的例子定义一个 StateObject 类它包含一个 int 字段和一个 ChangeState() 方法。在 ChangeState() 方法的实现代码中验证状态变量是否包含5。如果它包含就递增其值。下一条语句是Trace.Assert它立刻验证 state 现在是包含 6。在给包含 5 的变量递增了 1 后可能认为该变量的值就是 6。但事实不一定是这样。例如如果一个线程刚刚执行完 if(_state5)语句它就被其他线程抢占调度器运行另一个线程。第二个线程现在进入 if 体因为 state 的值仍是 5所以将它递增到 6。第一个线程现在再次被调度在下一条语句中State 递增到 7。这时就发生了争用条件并显示断言消息public class StateObject
{private int _state 5;public void ChangeState(int loop)
{if (_state 5){_state;If (_state ! 6){Console.WriteLine($Race conditon occurred after {loop} loops); Trace.Fail(race condition);}}_state 5;}
}下面通过给任务定义一个方法来验证这一点。SampleTask 类的 RaceCondition()方法将一个 StateObject 类作参数。在一个无限while循环中调用ChangeState() 方法。变量 i 仅用于显示断言消息中的循环次数。public class SampleTask
{public void RaceCondition(object o){Trace.Assert(o is StateObject, o must be of type StateObject); StateObject state o as StateObject;int i 0; while (true){state.ChangeState(i);}}
}在程序的 Main() 方法中新建了一个 StateObject 对象它由所有任务共享。通过使用传递给 Task 的 Run 方法的 lambda 表达式调用 RaceCondition 方法来创建 Task 对象。然后主线程等待用户输入。但是因为可能出现争用所以程序很有可能在读取用户输入前就挂起:public void RaceConditions()
{var state new StateObject(); for (int i 0; i 2; i){Task.Run(() new SampleTask().RaceCondition(state));}
}启动程序就会出现争用条件。多久以后出现第一个争用条件要取决于系统以及将程序构建为发布版本还是调试版本。如果构建为发布版本该问题的出现次数就会比较多因为代码被优化了。如果系统中有多个 CPU 或使用双核/四核 CPU其中多个线程可以同时运行则该问题也会比单核 CPU 的出现次数多。在单核CPU中因为线程调度是抢占式的也会出现该问题只是没有那么频繁。在我的系统上运行程序时显示在 85232 个循环后出现错误在另一次运行程序时显示在 70037 个循环后出现错误。多次启动应用程序总是会得到不同的结果。要避免该问题可以锁定共享的对象。这可以在线程中完成用下面的 lock 语句锁定在线程中共享的 state 变量。只有一个线程能在锁定块中处理共享的 state 对象。由于这个对象在所有的线程之间共享因此如果一个线程锁定了 state另一个线程就必须等待该锁定的解除。一旦接受锁定线程就拥有该锁定直到该锁定块的末尾才解除锁定。如果改变 state 变量引用的对象的每个线程都使用一个锁定就不会出现争用条件。public class SampleTask
{public void RaceCondition(object o){Trace.Assert(o is StateObject, o must be of type StateObject); StateObject state o as StateObject; int t 0;while (true){lock (state) // no race condition with this lock{state.ChangeState(i);}}}
}注意:在下载的示例代码中需要取消锁定语句的注释才能解决争用条件的问题。在使用共享对象时除了进行锁定之外还可以将共享对象设置为线程安全的对象。在下面的代码中, ChangeState() 方法包含一条 lock 语句。由于不能锁定 state 变量本身(只有引用类型才能用于锁定)因此定义一个object 类型的变量 sync将它用于lock 语句。如果每次 state 的值更改时都使用同一个同步对象来锁定就不会出现争用条件。public class StateObject
{private int state 5;private _object sync new object(); public void ChangeState(int loop) {lock (_sync){if (_state 5){_state;if (_state ! 6){Console.WriteLine($Race condition occured after {loop} loops);Trace.Fail($race condition at {loop});}}_state 5;}}} 微信公众号 Dotnet讲堂