C# Threading/Lock confusion

后端 未结 3 1499
轮回少年
轮回少年 2021-01-05 11:28

I have the following code:

var items = new List {\"1\", \"2\", \"3\"}; // 200 items
foreach(var item in items) {
  ThreadPool.QueueUserWorkItem         


        
相关标签:
3条回答
  • 2021-01-05 11:31

    This is a simple version of what I was alluding to. It uses a single event and does not poll or spin, and it's written so as to be reusable as well as allowing multiple work sets at the same time. The lambda expressions could be factored out, if that's more convenient for debugging.

    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
        }
    }
    
    0 讨论(0)
  • 2021-01-05 11:34

    The following note from MSDN documentation on ThreadPool says it all:

    The threads in the managed thread pool are background threads. That is, their IsBackground properties are true. This means that a ThreadPool thread will not keep an application running after all foreground threads have exited.

    Your application simply exits (by reaching end of Main) before your threads finish running.

    0 讨论(0)
  • 2021-01-05 11:34

    How about short and sweet?

        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();
        }
    
    0 讨论(0)
提交回复
热议问题