Лучше всего решение Марка, если вы просто хотите знать, когда все задания завершены, и вам не нужна более точная информация, чем эта (как вам кажется).
Если вы хотите, чтобы какой-то поток порождал задания, а другой - для получения уведомлений, вы можете использовать WaitHandle. Код намного длиннее.
int length = 10;
ManualResetEvent[] waits = new ManualResetEvent[length];
for ( int i = 0; i < length; i++ ) {
waits[i] = new ManualResetEvent( false );
ThreadPool.QueueUserWorkItem( (obj) => {
try {
} finally {
waits[i].Set();
}
} );
}
for ( int i = 0; i < length; i++ ) {
if ( !waits[i].WaitOne() )
break;
}
Метод WaitOne, как написано, всегда возвращает true, но я написал это так, чтобы вы помнили, что некоторые перегрузки принимают Timeout в качестве аргумента.