线程同步

时间:2010-06-22 05:19:26

标签: c# multithreading

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ThreadDemo
{
    class Program
    {
        static public  List<int> temp = new List<int >();
        static  public  List<Thread> worker = new List<Thread>();
        static public List<List<int>> Temporary = new List<List<int>>();
        static void Main(string[] args)
        {
            temp.add(20);
            temp.add(10);
            temp.add(5);
            foreach (int k in temp)
            {
                int z = 0;
                worker[z] = new Thread(() => { sample(k); });
                worker[z].Name = "Worker" + z.ToString();
                worker[z].Start();
                z++;
            }
        }
        public static void sample(int n)
        {
            List<int> local = new List<int>();
            for (int i = 0; i < n; i++)
            {
                local.Add(i);
            }
            Temporary.Add(local);
        }
    }
}

在这个程序中,我在主程序中启动foreach循环时遇到线程问题,创建三个线程并启动该线程。在第一个线程操作比其他线程长,所以需要一些时间但其他线程完成之前首先 由于临时的这个顺序被改变。我需要临时列表顺序和临时列表顺序相同。我可以用线程实现这个

4 个答案:

答案 0 :(得分:8)

有三个问题。首先,变量捕获:

foreach (int k in temp)
{
    int z = 0;
    worker[z] = new Thread(() => { sample(k); });
    ...
}

这是在lambda表达式中捕获变量 k,而不是k。解决方案是复制一份:

foreach (int k in temp)
{
    int z = 0;
    int copy = k;
    worker[z] = new Thread(() => { sample(copy); });
    ...
}

有关详细信息,请参阅Eric Lippert's blog post

其次,您总是填充worker[0],因为z将始终为0.如果您想填充其他元素,则需要声明{{1在外面。或者,您可以添加到列表中。

第三,存在不知道结果排序的问题。解决此问题的最简单方法实际上是将z转换为数组。再次,捕获变量的副本以保持正确的位置。正如ArsenMkrt所说,你还需要更新一个列表,这将涉及锁定。

您使用的是.NET 4.0(或者您可以)吗? Parallel Extensions使这一切变得更加简单,很多更简单。

答案 1 :(得分:2)

以下是对您的代码的快速抨击:

class Program
{
    static public List<int> temp = new List<int >();
    static public List<Thread> worker = new List<Thread>();
    static public List<List<int>> temporary = new List<List<int>>();
    static public object sync = new object();

    static void Main(string[] args)
    {
        temp.add(20);
        temp.add(10);
        temp.add(5);

        // Add a corresponding number of lists
        for( int i = 0; i < temp.Count; ++i)
        {
            temporary.Add(new List<int>);
        }

        // As Jon Skeet mentioned, z must be declared outside the for loop
        int z = 0;
        foreach (int k in temp)
        {
            // As Jon Skeet mentioned, you need to capture the value of k
            int copy = k;

            Thread t = new Thread(() => { Sample(copy, z); });
            t.Name = "Worker" + z.ToString();

            // set the thread to background, so your thread is 
            // properly closed when your application closes.
            t.IsBackground = true; 
            t.Start();

            // Calling worker[z] will always going to be out of bounds
            // because you didn't add anything to to the worker list,
            // therefore you just need to add the thread to the worker
            // list. Note that you're not doing anything with the worker
            // list, so you might as well not have it at all.
            worker.Add(t);
            z++;
        }
    }

    // Supply the order of your array
    public static void Sample(int n, int order)
    { 
        for (int i = 0; i < n; i++)
        {
            // Technically in this particular case you don't need to 
            // synchronize, but it doesn't hurt to know how to do it.
            lock(sync)
            {
                temporary[order].Add(i);
            }
        }
}

现在临时列表应该包含正确顺序的其他列表(与您的tmp顺序相同)。你的标题确实提到了日程安排,但我不确定你为什么需要在这里安排或者你究竟想要了解什么安排。

答案 2 :(得分:1)

首先,你的所有线程都是访问Temporary集合,因为List不是线程安全的,你应该让你的线程同步才能正常工作,第二个,你不能保证如果第一个线程首先启动,第一个线程将首先完成,这取决于核心如何安排线程。 要实现您的目标,您可以使用线程synchronization mechanisms

答案 3 :(得分:0)

如果您按顺序需要线程的结果,您可能应该以某种方式将它们传递给z,或者让它们返回结果并在主线程中按顺序连接每个线程。

除此之外,你可能有点搞砸了。就其本质而言,无论您需要做什么,线程都会在错误的时间运行。您不能依赖它们随时开始或停止;如果可以的话,整类并发问题就会消失。

我建议你谨慎使用线程。在单核,单CPU机器上,您的线程示例运行速度比没有线程的正常编码解决方案慢,因为启动线程会产生开销。我见过线程的唯一一次非常有用,有时你真的需要一次做两件事。就像在等待输入时保持UI工作或在后台做一些任意大工作一样。为了拥有它们而拥有线程最终会让你发疯。