It's not a bad idea to reuse threads. You have two options: 1) using thread pool, 2) having "permanent" thread (with lifetime maybe close to the lifetime of your process) pushing different tasks on it when required and throttling it between tasks the way it spend not CPU time and waits to be waken up by a new task.
First way is simple. Get an idea of thread pool:
http://en.wikipedia.org/wiki/Thread_pool_pattern[
^]. With .NET, use the class
System.Threading.ThreadPool
, see
http://msdn.microsoft.com/en-us/library/system.threading.threadpool.aspx[
^].
The thread pool method is good when you cannot precisely pre-determine the number of threads working in parallel. Nevertheless, having too many threads should be avoided.
If you really want to write to no more than three files (or so) at the same time, you can use the schema with "permanent" threads and throttling. Create such threads using regular thread constructor,
System.Threading.Thread
,
http://msdn.microsoft.com/en-us/library/system.threading.thread.aspx[
^].
First of all, to make it all accurate, make your the thread body an instance (non-static) method of some class, a thread wrapper. In this way, you can encapsulate the thread in this class and make all the data of the wrapper class accessible to the thread at once, via "this" reference to the instance of the wrapper class passed implicitly. See my past solutions with detailed explanation here:
How to pass ref parameter to the thread[
^],
change paramters of thread (producer) after it started[
^].
The body of the thread should repeat in cycle waiting for the instance of
System.Threading.EventWaitHandle
,
System.Threading.AutoResetEvent
,
System.Threading.ManualResetEvent
, see:
http://msdn.microsoft.com/en-us/library/system.threading.eventwaithandle.aspx[
^],
http://msdn.microsoft.com/en-us/library/system.threading.autoresetevent.aspx[
^],
http://msdn.microsoft.com/en-us/library/system.threading.manualresetevent.aspx[
^].
When you thread calls the method
WaitOne
of the event wait handle, it is put to the special wait state; switched off but the OS and never scheduled back to execution until waken up by the expiration time (if any),
Thread.Abort
or by the call to the method
Set
of the same instance of the event wait handle called by other thread. In this way, this other thread can "put" tasks to you thread and thread wrapper and then let your thread to go using
Set
.
More advanced (and maybe easier in usage) approach using this technique is using a
blocking queue. You can find the implementation in my article:
"Simple Blocking Queue for Thread Communication and Inter-thread Invocation". For .NET v. 4.0, such queue already exists, but I explain the usage patterns and provide detail usage code, including another interesting and useful case when the elements of the queue are delegate instances; in this way, you can push very different tasks to the queue and sequentially execute them in the same thread, in parallel with several threads.
—SA