我有以下代码:
var items = new List<string> {"1", "2", "3"}; // 200 items
foreach(var item in items) {
ThreadPool.QueueUserWorkItem((DoWork), item);
}
private void DoWork(object obj)
{
lock(this)
{
using(var sw = File.AppendText(@"C:\somepath.txt")
{
sw.WriteLine(obj);
}
}
}
由于线程,出于某种原因,我得到了写入文件的200个项目的随机数。 60或127或有时只有3.如果我删除ThreadPool并在原始foreach循环内写入,则所有200个项目都会成功写入。
不确定为什么会这样?
感谢您的帮助。
答案 0 :(得分:9)
MSDN documentation on ThreadPool
的以下说明说明了一切:
托管线程池中的线程是后台线程。也就是说,他们的
IsBackground
属性是真的。 这意味着ThreadPool
线程不会在所有前台线程退出后继续运行。
您的应用程序只是在线程完成运行之前退出(到达Main
的末尾)。
答案 1 :(得分:2)
这是我所暗示的简单版本。它使用单个事件并且不进行轮询或旋转,并且它被编写为可重用,并且允许同时允许多个工作集。如果对调试更方便,可以将lambda表达式考虑在内。
class Program
{
static void Main(string[] args)
{
var items = new string[] { "1", "2", "3", "300" };
using (var outfile = File.AppendText("file.txt"))
{
using (var ws = new WorkSet<string>(x =>
{ lock (outfile) outfile.WriteLine(x); }))
foreach (var item in items)
ws.Process(item);
}
}
public class WorkSet<T> : IDisposable
{
#region Interface
public WorkSet(Action<T> action)
{ _action = action; }
public void Process(T item)
{
Interlocked.Increment(ref _workItems);
ThreadPool.QueueUserWorkItem(o =>
{ try { _action((T)o); } finally { Done(); } }, item);
}
#endregion
#region Advanced
public bool Done()
{
if (Interlocked.Decrement(ref _workItems) != 0)
return false;
_finished.Set();
return true;
}
public ManualResetEvent Finished
{ get { return _finished; } }
#endregion
#region IDisposable
public void Dispose()
{
Done();
_finished.WaitOne();
}
#endregion
#region Fields
readonly Action<T> _action;
readonly ManualResetEvent _finished = new ManualResetEvent(false);
int _workItems = 1;
#endregion
}
}
答案 2 :(得分:0)
短而甜的怎么样?
static int wrkThreads = 0;
static readonly EventWaitHandle exit = new ManualResetEvent(false);
static readonly object syncLock = new object();
static void Main( string[] items )
{
wrkThreads = items.Length;
foreach ( var item in items )
ThreadPool.QueueUserWorkItem(( DoWork ), item);
exit.WaitOne();
}
static void DoWork( object obj )
{
lock ( syncLock ) {
/* Do your file work here */
}
if ( Interlocked.Decrement(ref wrkThreads) == 0 )
exit.Set();
}