`
varsoft
  • 浏览: 2439670 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

[原创] 难道调用ThreadPool.QueueUserWorkItem()的时候,真是必须调用Thread.Sleep(N)吗?

阅读更多

开门见山,下面的例子中通过调用ThreadPool.QueueUserWorkItem(WaitCallback callBack, object state)的方式实现异步调用:

   1: class Program
<!--CRLF-->
   2: { 
<!--CRLF-->
   3:     static void Main(string[] args)
<!--CRLF-->
   4:     {
<!--CRLF-->
   5:          List<Action> actions = new List<Action>();
<!--CRLF-->
   6:         actions.Add(() => Console.WriteLine("A1"));
<!--CRLF-->
   7:         actions.Add(() => Console.WriteLine("A2"));
<!--CRLF-->
   8:         actions.Add(() => Console.WriteLine("A3"));
<!--CRLF-->
   9:         actions.Add(() => Console.WriteLine("A4")); 
<!--CRLF-->
  10: 
<!--CRLF-->
  11:         foreach (var action in actions)
<!--CRLF-->
  12:         {
<!--CRLF-->
  13:             ThreadPool.QueueUserWorkItem(state => action(), null);
<!--CRLF-->
  14:         } 
<!--CRLF-->
  15: 
<!--CRLF-->
  16:         Console.Read();
<!--CRLF-->
  17:     }
<!--CRLF-->
  18: } 
<!--CRLF-->

但是出现错误的输出结果:

image

解决的方案就是在每次For循环中,调用Thread.Sleep休眠当前线程,哪怕是1ms:

   1: class Program
<!--CRLF-->
   2: { 
<!--CRLF-->
   3:     static void Main(string[] args)
<!--CRLF-->
   4:     {
<!--CRLF-->
   5:          List<Action> actions = new List<Action>();
<!--CRLF-->
   6:         actions.Add(() => Console.WriteLine("A1"));
<!--CRLF-->
   7:         actions.Add(() => Console.WriteLine("A2"));
<!--CRLF-->
   8:         actions.Add(() => Console.WriteLine("A3"));
<!--CRLF-->
   9:         actions.Add(() => Console.WriteLine("A4")); 
<!--CRLF-->
  10: 
<!--CRLF-->
  11:         foreach (var action in actions)
<!--CRLF-->
  12:         {
<!--CRLF-->
  13:             ThreadPool.QueueUserWorkItem(state => action(), null);
<!--CRLF-->
  14: 
<!--CRLF-->
  15:             Thread.Sleep(1);
<!--CRLF-->
  16:         } 
<!--CRLF-->
  17: 
<!--CRLF-->
  18:         Console.Read();
<!--CRLF-->
  19:     }
<!--CRLF-->
  20: }
<!--CRLF-->
  21: 
<!--CRLF-->

这次能够输出正确的结果:

image

我们也看到很多人确实是这么做的。但是如果真是必须这样的话,这样的编程方式很难让我接受,不知道大家有何高见。

在老赵的提示下,醒悟过来:由于被置于ThreadPool中的操作时异步的,还没有来的执行的时候,action已经被for循环改变,永远是同一个action对象! 呵呵,脑袋有时候有点转不过弯!

所以正确的写法是:

   1: foreach (var action in actions)
<!--CRLF-->
   2: {
<!--CRLF-->
   3: var a = action;
<!--CRLF-->
   4: ThreadPool.QueueUserWorkItem(state => a(), null);
<!--CRLF-->
   5: }
<!--CRLF-->

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics