I'm currently working on a multithread project involving several time consuming tasks running in parallel.
Every task is logging in the same file, and I need to keep it tidy (with the right order), so I found a way to log "task by task":
- When a task must write to the log file, instead I write my logs in a Dictionary :
_logList[id].Add(message) - This Dictionary has Key = ThreadID, Value = logs of the worker with this ID (list of string)
- The ThreadID comes from
Thread.CurrentThread.ManagedThreadId
Here is how I launch my BackgroundWorkers:
foreach (MyTask task in List<MyTask> tasks)
{
BackgroundWorker bg = new BackgroundWorker();
bg.DoWork += bgworker_DoWork;
bg.RunWorkerCompleted += bgworker_RunWorkerCompleted;
List<object> arguments = new List<object>() { task, args1 };
bg.RunWorkerAsync(arguments);
}
The bgworker_DoWork delegate is the time consuming tasks, writing logs.
Then, when a task is over, the BackgroundWorker runs the delegate bgworker_RunWorkerCompleted, which basically ends the task and writes the corresponding log, in the right order:
Log.FlushWrite((int)result[2]); -- result[2] contains the threadId to flush
And FlushWrite only writes to the log file the list of logs of the threadId:
WriteMessageToFile(_logList[id]);
Most the time, this works. But sometimes, I see a weird behavior:
- Several tasks are using the same ThreadID
- When the first task N of the ThreadID X has ended, it calls the RunWorkerCompleted delegate, and flushes its logs + only a part of the next task N+1 of the ThreadID X (because the task has not ended yet)
- When the task N+1 really ends, it flushes the remaining logs to write, but the log file is a mess because it is not tidy!
I know a managed thread id might be recycled and reused, but imo the only way for this situation to happen is that the thread is already reused (new call to DoWork) when the BackgroundWorker running has not yet called the RunWorkerCompleted
Am I right? Is there something I did not understand of this situation?
Maybe using a ManagedThreadId as a key of a Dictionary is a bad practice in that case?
Thanks for your help :)