Во-первых, сколько времени рабочие выполняются? потоки пула должны обычно использоваться для недолгих задач - если они собираются работать некоторое время, рассмотреть ручные потоки.
Ре проблема; необходимо ли на самом деле заблокировать основной поток? Можно ли использовать обратный вызов вместо этого? Если так, что-то как:
int running = 1; // start at 1 to prevent multiple callbacks if
// tasks finish faster than they are started
Action endOfThread = delegate {
if(Interlocked.Decrement(ref running) == 0) {
// ****run callback method****
}
};
foreach(var o in collection)
{
var tmp = o; // avoid "capture" issue
Interlocked.Increment(ref running);
ThreadPool.QueueUserWorkItem(delegate {
DoSomeWork(tmp); // [A] should handle exceptions internally
endOfThread();
});
}
endOfThread(); // opposite of "start at 1"
Это - довольно легкое (никакие примитивы ОС) способ отследить рабочих.
, Если Вы потребность для блокирования можно сделать то же использование Monitor
(снова, избежав объекта ОС):
object syncLock = new object();
int running = 1;
Action endOfThread = delegate {
if (Interlocked.Decrement(ref running) == 0) {
lock (syncLock) {
Monitor.Pulse(syncLock);
}
}
};
lock (syncLock) {
foreach (var o in collection) {
var tmp = o; // avoid "capture" issue
ThreadPool.QueueUserWorkItem(delegate
{
DoSomeWork(tmp); // [A] should handle exceptions internally
endOfThread();
});
}
endOfThread();
Monitor.Wait(syncLock);
}
Console.WriteLine("all done");
Вот эвристика, которой я следую:
Предпочитайте выражения LINQ лямбдам, когда у вас есть соединения.
Я думаю, что лямбды с объединениями выглядят беспорядочно и их трудно читать.
Я обычно использую ReSharper, чтобы помочь мне преобразовать вещи в цепочки методов и лямбды, что помогает мне довольно легко перемещаться туда и обратно.
var result = from g in grocery
join f in fruit on g.fruitId equals f.fruitId into tempFruit
join v in veggie on g.vegid equals v.vegid into tempVegg
from joinedFruit in tempFruit.DefaultIfEmpty()
from joinedVegg in tempVegg.DefaultIfEmpty()
select new { g.fruitId, g.vegid, fname = ((joinedFruit == null) ? string.Empty : joinedFruit.fname), vname = ((joinedVegg == null) ? string.Empty : joinedVegg.vname) };
А затем использование опции ReSharper для преобразования LINQ в цепочку методов равно следующее:
var result =grocery .GroupJoin(fruit, g => g.fruitId, f => f.fruitId, (g, tempFruit) => new {g, tempFruit})
.GroupJoin(veggie, @t => @t.g.vegid, v => v.vegid, (@t, tempVegg) => new {@t, tempVegg})
.SelectMany(@t => @t.@t.tempFruit.DefaultIfEmpty(), (@t, joinedFruit) => new {@t, joinedFruit})
.SelectMany(@t => @t.@t.tempVegg.DefaultIfEmpty(),(@t, joinedVegg) =>
new
{
@t.@t.@t.g.fruitId,
@t.@t.@t.g.vegid,
fname = ((@t.joinedFruit == null) ? string.Empty : @t.joinedFruit.fname),
vname = ((joinedVegg == null) ? string.Empty : joinedVegg.vname)
});
Допустим, результат менее желателен, но, по крайней мере, помогает с чего-то начать понимание синтаксиса.
Вы можете взглянуть на 101 LINQ Samples и C # 3.0 ПЕРЕВОД ВЫРАЖЕНИЯ ЗАПРОСА ЛИСТ
Загрузить LINQPad ; он поставляется со встроенными примерами для изучения LINQ.