1

我有一个主线程,我确实创建了另一个 n 线程。每个 n 线程正在填充一个List<String>. 当所有线程都完成后,它们会被加入,我希望将所有这些 n 线程列表放在主线程的List<List<String>>BUT 中。主线程应该能够对其进行操作List<List<String>>。每个 n 线程贡献了一个List<String>.

我有 c# .NET 3.5,我想避免static List<List<String>>

            Thread t = new Thread(someObjectForThreading.goPopulateList);
            list_threads.Add(t);
            list_threads.last().start()

list_threads 中的所有线程继续并填充它们的列表,当它们完成时,我想要类似的东西

 //this = mainThread
 this.doSomethingWith(List<List<String>>)

编辑:嗯没有“标准概念”如何解决这样的任务?许多线程在一个列表上操作,当所有线程都加入时,主线程可以继续对列表进行操作。

Edit2:不能是静态的。List<List<String>> listOfLists可以public or private。首先,我需要 n 线程来操作(并锁定)listOfLists,插入它们的列表,并且在所有 n 线程完成插入它们的列表之后,我将加入线程并且主线程可以继续进行业务逻辑并在listOfLists

我想我会重新阅读http://www.albahari.com/threading/的某些部分报告回来

4

4 回答 4

5

这是一个使用等待句柄(在 ManualResetEvent 的情况下)的简单实现,以允许每个工作线程向主线程发出信号,表明它已完成其工作。我希望这有点不言自明:

private List<List<string>> _listOfLists;

public void CreateListOfLists()
{
    var waitHandles = new List<WaitHandle>();

    foreach (int count in Enumerable.Range(1, 5))
    {
        var t = new Thread(CreateListOfStringWorker);
        var handle = new ManualResetEvent(false);
        t.Start(handle);
        waitHandles.Add(handle);
    }

    // wait for all threads to complete by calling Set()
    WaitHandle.WaitAll(waitHandles.ToArray());

    // do something with _listOfLists
    // ...
}

public void CreateListOfStringWorker(object state)
{
    var list = new List<string>();
    lock (_listOfLists)
    {
        _listOfLists.Add(list);
    }

    list.Add("foo");
    list.Add("bar");

    ((ManualResetEvent) state).Set(); // i'm done
}

请注意,当我将每个线程的列表添加到列表的主列表时,我只是在锁定。没有必要为每个添加锁定主列表,因为每个线程都有自己的列表。有道理?

编辑:

使用等待句柄的目的是在处理列表列表之前等待每个线程完成。如果您不等待,那么您可能会在工作人员仍在向其中添加字符串时尝试枚举其中一个 List 实例。这将导致抛出 InvalidOperationException,并且您的线程将死亡。您不能枚举一个集合并同时修改它。

于 2012-08-30T21:31:11.523 回答
1

而不是使static List<List<String>>make 成为本地List<List<String>>并将其传递给线程将运行的对象。当然,您需要将其包装List在同步包装器中,因为它被多个线程访问。

List<List<String>> list = ArrayList.synchronized(new ArrayList<List<String>>());

// later
SomeObject o = new SomeObjectForThreading(list);
Thread t = new Thread(o.goPopulateList);
list_threads.Add(t);
list_threads.last().start();

// even later
this.doSomethingWith(list);

o.goPopulateList中,您可能有

List<String> temp = new ArrayList<String>();
temp.add(random text);
temp.add(other random text);
this.list.add(temp); // this.list was passed in at construct time
于 2012-08-30T21:09:43.360 回答
1

我将为每个线程提供一个回调方法,该方法更新主线程中的列表,并受lock语句保护。

编辑:

class Program
{
    static List<string> listOfStuff = new List<string>();

    static void Main(string[] args)
    {
        List<Thread> threads = new List<Thread>();
        for (int i = 0; i < 20; i++)
        {
            var thread = new Thread(() => { new Worker(new AppendToListDelegate(AppendToList)).DoWork(); });
            thread.IsBackground = true;
            threads.Add(thread);
        }
        threads.ForEach(n => n.Start());
        threads.ForEach(n => n.Join());
        Console.WriteLine("Count: " + listOfStuff.Count());
        Console.ReadLine();
    }

    static void AppendToList(string arg)
    {
        lock (listOfStuff)
        {
            listOfStuff.Add(arg);
        }
    }
}

public delegate void AppendToListDelegate(string arg);
class Worker
{
    AppendToListDelegate Appender;

    public Worker(AppendToListDelegate appenderArg)
    {
        Appender = appenderArg;
    }

    public void DoWork()
    {
        for (int j = 0; j < 10000; j++)
        {
            Appender(Thread.CurrentThread.ManagedThreadId.ToString() + "." + j.ToString());
        }
    }
}
于 2012-08-30T21:12:58.033 回答
0
private void someObjectForThreading.goPopulateList()
{
    Do threaded stuff...
    populate threaded list..

    All done..
    for (List list in myThreadedList)
    {
        myMainList.Add(list);
    }
}
于 2012-08-30T21:28:25.600 回答