C # Confusion Threading / Lock

I have the following code:

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); } } } 

Due to streaming, for some reason, I get a random number of 200 items written to a file. 60 or 127 or sometimes only 3. If I delete ThreadPool and just write inside the source foreach loop, all 200 elements will be successfully written.

Not sure why this is happening?

Thank you for your help.

+6
source share
3 answers

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

Threads in a managed thread pool are background threads. That is, their IsBackground properties are correct. This means that the ThreadPool thread will not support the application running after all front threads exit .

Your application just shuts down (reaching the end of Main ) before your threads run out.

+9
source

This is a simple version of what I mentioned. It uses one event and does not conduct polling or rotation, and it is written so that it can be reused, and also allow multiple sets of work at the same time. Lambda expressions can be considered if it is 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 } } 
+2
source

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
source

All Articles