Мне кажется, я нашел достаточно аккуратный способ сделать это. Ключевым моментом является то, что если бы у меня был выделенный фоновый поток, выполняющий эту обработку, то решение довольно простое и может выглядеть примерно так:
AutoResetEvent ev = new AutoResetEvent(false);
// Called on a background thread
void ThreadProc()
{
int lastProcessed = 0;
while (true)
{
// Perform our processing as before
for (int i = lastProcessed; i < this.items.Count; i++)
{
this.ProcessItem(this.items[i]);
}
// We have processed all items currently in the list, wait for some more
ev.WaitOne();
}
}
void OnNewItems()
{
ev.Set();
}
Отсутствующей ссылкой является метод ThreadPool.RegisterWaitForSingleObject
, который позволяет преобразовать его в пул потоков вместо выделенного потока:
int lastProcessed = 0;
void StartProcessing()
{
ThreadPool.RegisterWaitForSingleObject(
this.ev,
new WaitOrTimerCallback(WaitProc),
null, // All state stored in the class instance itself
-1, // Always wait indefinitely for new items
true // Only execute once - each callback registers a new wait handle ensuring
// that a maximum of 1 task is running Process at any one time
);
}
void WaitProc(object state, bool timedOut)
{
// Perform our processing as before
for (int i = lastProcessed; i < this.items.Count; i++)
{
this.ProcessItem(this.items[i]);
}
// We have processed all items currently in the list, wait for some more
this.StartProcessing();
}
Это устанавливает цикл так же, как и раньше, за исключением того, что мы не блокируем поток, ожидающий событие сброса.