Вопрос о синхронизации потоков - PullRequest
1 голос
/ 09 июня 2009

У меня есть вопрос о ситуации с нитями.

Предположим, у меня есть 3 потока: производитель, помощник и потребитель. поток производителя находится в рабочем состоянии (а два других находятся в состоянии ожидания), и когда это сделано, он вызывает invoke, но проблема в том, что он должен вызывать только вспомогательный поток, а не потребитель, тогда как он может убедиться, что после освобождения ресурсов извлекается только вспомогательным потоком, а затем потребительским потоком.

заранее спасибо

Ответы [ 4 ]

2 голосов
/ 09 июня 2009

Или вы уже подумали, что иногда наличие отдельных потоков - это скорее проблема, чем решение?

Если вы действительно хотите, чтобы операции в одном потоке были строго сериализованы с операциями в другом потоке, возможно, более простое решение - отбросить второй поток и структурировать код так, чтобы первый поток выполнял операции в желаемом порядке.

Это не всегда возможно, но об этом нужно помнить.

1 голос
/ 09 июля 2009

Вы можете использовать очереди, чтобы помочь вам с замками вокруг них. 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, то спит - но сигналы чище и эффективнее).

Этот подход позволит вам обрабатывать данные с разной скоростью (что может привести к проблемам с памятью).

1 голос
/ 09 июня 2009

Вспомогательный поток на самом деле является просто потоком потребителя / производителя. Напишите некоторый код для помощника, как если бы любой другой потребитель принял результаты производителя. После этого напишите какой-нибудь код для помощника, как для любого другого производителя, и подключите его к своей потребительской ветке.

1 голос
/ 09 июня 2009

У вас может быть, например, два мьютекса (или что вы используете): один для производителя и помощника, а другой для производителя и потребителя

Producer:
  //lock helper
     while true
  {
   //lock consumer
   //do stuff
   //release and invoke helper
   //wait for helper to release
   //lock helper again
   //unlock consumer
   //wait consumer
  }

Остальные просто блокируются и разблокируются нормально.

Другой возможный подход (возможно, лучше) заключается в использовании мьютекса для производителя / помощника и другого помощника / потребителя; или, может быть, распределить задачи этого вспомогательного потока между двумя другими потоками. Не могли бы вы дать более подробную информацию?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...