是否有更优雅的方式编写以下语法?
Thread t0 = new Thread(new ParameterizedThreadStart(doWork));
t0.Start('someVal');
t0.Join();
Thread t1 = new Thread(new ParameterizedThreadStart(doWork));
t1.Start('someDiffVal');
t1.Join();
假设我们想传递20个不同的值,设置它的最佳方法是什么?在最后循环并加入?
如果未实例化新线程(如下所示),则无法重新启动线程。例如:
Thread t1 = new Thread(new ParameterizedThreadStart(doWork));
t1.Start('someVal');
t1.Start('someDiffVal');
答案 0 :(得分:7)
你为什么要开始一个线程然后立即加入呢?
我通常会这样做:
List<Thread> threads = new List<Thread>();
foreach (string item in items)
{
string copy = item; // Important due to variable capture
ThreadStart ts = () => DoWork(copy); // Strongly typed :)
Thread t = new Thread(ts);
t.Start();
threads.Add(t);
}
foreach (Thread t in threads)
{
t.Join();
}
答案 1 :(得分:2)
另一个选项(在.NET 4.0中,或使用CTP)将是Parallel.ForEach
的一种形式。但是,不一定可行。我还看到了一个在这里使用IDisposable
的好博客条目(不记得是谁),即
using(StartThread(arg1))
using(StartThread(arg2))
{
}
其中Dispose()方法在生成的线程上进行了连接 - 即退出块时,一切都已完成。很可爱。
答案 2 :(得分:0)
为什么不让你的参数成为类的一部分,使它们成为属性,并让get / set方法锁定它们?如果您有足够的参数,请将参数对象本身作为对象的属性,然后锁定该参数块。如:
class GonnaDoSomeThreading {
private Object mBlockLock = new Object();
private MyParameterBlock mBlock;
public MyParameterBlock Block {
get {
MyParameterBlock tmp;
lock (mBlockLock){
tmp = new MyParameterBlock(mBlock); //or some other cloning
}
return tmp; //use a tmp in order to make sure that modifications done
//do not modify the block directly, but that modifications must
//be 'committed' through the set function
}
set { lock (mBlockLock){ mBlock = value; } }
}
}
然后按照已建议的方式执行您的线程池。这样,您就可以锁定数据访问,这样如果所有线程都需要它,它们就可以相互等待。
如果您正在为图像处理(可以同时完成许多并行对象)这样做,那么将数据分解为个性化块可能更好。 IE,比如你想在一个较大的图像上运行一些卷积,所以想把它分成两半。然后,您可以使用“Fragmentimage”函数创建您将单独处理的图像块,然后使用“MergeFragments”函数调用以加入所有结果。所以你的片段看起来像:
class ThreadWorkFragment {
<image type, like ushort>[] mDataArray;
bool mDone;
}
锁定该片段(即,一个对象和片段的列表,每个都有一个锁等等),这样当线程访问它的片段时,它最终可以声明它已经“完成”,释放锁定,然后你可以有一个最终的合并函数,只等待那些已经标记的布尔值。这样,如果其中一个线程在设置完成之前就死了,并且你知道线程已经死了,那么你也知道线程没有完成它的工作,你需要做一些错误恢复;如果你只是等待连接发生,那么线程可能仍然搞砸了它的片段。
但是,基于您试图解决的问题,有很多具体的想法要实施。