我有一个mainthread,我确实创建了另一个n-threads。每个n线程都填充List<String>
。当所有线程都完成后,它们会被连接起来,我希望所有这些n线程List都在主线程的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中的所有线程都会继续并填充它们的List,当它们完成时我希望有类似的东西
//this = mainThread
this.doSomethingWith(List<List<String>>)
编辑:嗯,没有&#34;标准概念&#34;如何解决这样的任务?许多线程在列表上运行,当所有线程都加入时,mainthread可以继续操作列表。
Edit2: List<List<String>> listOfLists
不得为静态。可以是public or private
。首先,我需要n个线程来操作(并锁定)listOfLists,插入它们的List,并且在完成插入列表的所有n线程之后,我将加入线程并且mainthread可以继续使用businesslogic并在{{1 }}
我想我会重新阅读http://www.albahari.com/threading/报告的某些部分
答案 0 :(得分: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添加到列表的主列表时只是锁定。没有必要为每个添加锁定主列表,因为每个线程都有自己的List。有意义吗?
修改强>
使用等待句柄的目的是在处理列表列表之前等待每个线程完成。如果您不等待,那么当工作者仍在向其添加字符串时,您可能会尝试枚举其中一个List实例。这将导致抛出InvalidOperationException,并且您的线程将会死亡。您无法枚举集合并同时对其进行修改。
答案 1 :(得分:1)
而不是让static List<List<String>>
创建一个本地List<List<String>>
并将其传递给Object,线程将运行。当然,您需要将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
答案 2 :(得分: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());
}
}
}
答案 3 :(得分:0)
private void someObjectForThreading.goPopulateList()
{
Do threaded stuff...
populate threaded list..
All done..
for (List list in myThreadedList)
{
myMainList.Add(list);
}
}