C#线程/锁定混乱

时间:2009-08-14 23:50:33

标签: c# multithreading locking

我有以下代码:

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个项目都会成功写入。

不确定为什么会这样?

感谢您的帮助。

3 个答案:

答案 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();
    }