无序线程问题

我在这里问过关于锁的问题,人们回答我的锁实现没有问题。 但我抓住了问题。 这是相同的锁实现,我得到了奇怪的结果。 我希望看到数字从1开始,但它从5开始。例如,如下所示。

class Program { static object locker = new object(); static void Main(string[] args) { for (int j = 0; j < 100; j++) { (new Thread(new ParameterizedThreadStart(dostuff))).Start(j); } Console.ReadKey(); } static void dostuff(dynamic input) { lock (locker) { Console.WriteLine(input); } } } 

代码很好。 但是你无法保证线程执行的顺序。当我运行代码时,我得到:

0 1 3 5 2 4 6 10 9 11 7 12 8等

如果需要以指定的顺序运行线程,则可以考虑使用ThreadPool.QueueUserWorkItem

 class Program { static object locker = new object(); static EventWaitHandle clearCount =new EventWaitHandle(false, EventResetMode.ManualReset); static void Main(string[] args) { for (int j = 0; j < 100; j++) { ThreadPool.QueueUserWorkItem(dostuff, j); } clearCount.WaitOne(); } static void dostuff(dynamic input) { lock (locker) { Console.WriteLine(input); if (input == 99) clearCount.Set(); } } } 

将锁放在你放置的位置是没有意义的,因为你没有锁定改变多个线程共享的值的代码。 您锁定的代码部分根本不会更改任何变量。

数字乱序的原因是因为线程不能保证以任何特定的顺序启动,除非你做像@Mikael Svenson建议的那样。

有关共享变量的示例,请使用以下代码:

 class Program { static object locker = new object(); static int count=0; static void Main(string[] args) { for (int j = 0; j < 100; j++) { (new Thread(new ParameterizedThreadStart(dostuff))).Start(j); } Console.ReadKey(); } static void dostuff(object Id) { lock (locker) { count++; Console.WriteLine("Thread {0}: Count is {1}", Id, count); } } } 

您可能会看到线程编号不是有序的,但是计数是。 如果删除lock语句,则计数也不会按顺序排列。

你有几个问题和错误的假设。

  • 建议不要以这种方式创建100个线程。
  • 线程不会按照它们启动的顺序执行。
  • 将锁放置在您拥有它的位置将有效地序列化线程的执行,立即消除您希望通过使用线程获得的任何优势。

最好的使用方法是将问题划分为单独的独立块,这些块可以使用尽可能少的线程同步来同时计算。 这些分区应该在很小且相当静态的线程上执行。 您可以使用ThreadPoolParallelTask类来执行此操作。

我使用Parallel.For方法包含了一个示例模式。 为了使示例易于理解,假设您有一个要克隆的对象列表并将其放入单独的列表中。 让我们假设克隆操作很昂贵,并且您希望并行化克隆许多对象。 以下是你将如何做到这一点。 请注意lock关键字的放置和限制使用。

 public static void Main() { List original = GetCloneableObjects(); List copies = new List(); Parallel.For(0, 100, i => { ICloneable cloneable = original[i]; ICloneable copy = cloneable.Clone(); lock (copies) { copies.Add(copy); } }); }