Вы можете использовать очереди, чтобы помочь вам с замками вокруг них.
Producer работает над чем-то, производит его и помещает в очередь помощников.
Помощник берет это, делает что-то с этим, и затем помещает это в очередь потребителя.
Потребитель берет его, потребляет и продолжает.
Примерно так:
Queue<MyDataType> helperQ, consumerQ;
object hqLock = new object();
object cqLock = new object();
// producer thread
private void ProducerThreadFunc()
{
while(true)
{
MyDataType data = ProduceNewData();
lock(hqLock)
{
helperQ.Enqueue(data);
}
}
}
// helper thread
private void HelperThreadFunc()
{
while(true)
{
MyDataType data;
lock(hqLock)
{
data = helperQ.Dequeue();
}
data = HelpData(data);
lock(cqLock)
{
consumerQ.Enqueue(data);
}
}
}
// consumer thread
private void ConsumerThreadFunc()
{
while(true)
{
MyDataType data;
lock(cqLock)
{
data = consumerQ.Dequeue();
}
Consume(data);
}
}
ПРИМЕЧАНИЕ. Вам нужно будет добавить больше логики в этот пример, чтобы обеспечить его пригодность для использования. Не ожидайте, что это будет работать как есть. В основном, используйте сигналы для одного потока, чтобы сообщить другому, что данные доступны в его очереди (или, в худшем случае, опросите размер очереди, чтобы убедиться, что он больше 0, если он равен 0, то спит - но сигналы чище и эффективнее).
Этот подход позволит вам обрабатывать данные с разной скоростью (что может привести к проблемам с памятью).