ファイル名ごとにスレッドを開始するのではなく、ファイル名をキューに入れてから、3つのスレッドを開始してそれらを処理します。または、メインスレッドが解放されたので、2つのスレッドを起動して、メインスレッドも動作させます。
Queue<string> MyQueue;
void MyProc()
{
string[] filenames = Directory.GetFiles(...);
MyQueue = new Queue(filenames);
// start two threads
Thread t1 = new Thread((ThreadStart)ProcessQueue);
Thread t2 = new Thread((ThreadStart)ProcessQueue);
t1.Start();
t2.Start();
// main thread processes the queue, too!
ProcessQueue();
// wait for threads to complete
t1.Join();
t2.Join();
}
private object queueLock = new object();
void ProcessQueue()
{
while (true)
{
string s;
lock (queueLock)
{
if (MyQueue.Count == 0)
{
// queue is empty
return;
}
s = MyQueue.Dequeue();
}
ProcessFile(s);
}
}
もう1つのオプションは、セマフォを使用して、動作しているスレッドの数を制御することです。
Semaphore MySem = new Semaphore(3, 3);
void MyProc()
{
string[] filenames = Directory.GetFiles(...);
foreach (string s in filenames)
{
mySem.WaitOne();
ThreadPool.QueueUserWorkItem(ProcessFile, s);
}
// wait for all threads to finish
int count = 0;
while (count < 3)
{
mySem.WaitOne();
++count;
}
}
void ProcessFile(object state)
{
string fname = (string)state;
// do whatever
mySem.Release(); // release so another thread can start
}
前者は、処理されるファイル名ごとにスレッドを開始および停止するオーバーヘッドがないため、パフォーマンスがいくらか向上します。2つ目は、はるかに短くてクリーンであり、スレッドプールを最大限に活用します。おそらく、パフォーマンスの違いに気付かないでしょう。