Управление голоданием ThreadPool в многопоточном процессоре рабочей очереди? - PullRequest
3 голосов
/ 24 сентября 2008

Я исследую конструкцию процессора рабочей очереди, в котором QueueProcessor извлекает объект шаблона команд из очереди и выполняет его в новом потоке.

Я пытаюсь разобраться с потенциальным сценарием блокировки очереди, в котором вложенные команды могут привести к тупику.

Е.Г.

Объект FooCommand помещается в очередь, которую затем QueueProcessor выполняет в своем собственном потоке.

Выполнение FooCommand помещает BarCommand в очередь.

Если предположить, что максимально допустимое количество потоков составляет только 1 поток, QueueProcessor будет находиться в тупиковом состоянии, поскольку FooCommand бесконечно ожидает завершения BarCommand.

Как можно справиться с этой ситуацией? Является ли объект очереди правильным объектом для работы? Существуют ли какие-либо сдержки и противовесы, которые можно использовать для решения этой проблемы?

Большое спасибо. (приложение использует C # .NET 3.0)

Ответы [ 5 ]

2 голосов
/ 24 сентября 2008

Вы можете изменить дизайн так, чтобы FooCommand не использовал очередь для запуска BarCommand, а запускал ее напрямую, или вы могли бы разделить FooCommand на две части и иметь первую половину остановки сразу после постановки в очередь BarCommand, и иметь очередь BarCommand, а вторая иметь очередь FooCommand после того, как он сделал свою работу.

2 голосов
/ 24 сентября 2008

Очередь неявно предполагает асинхронную модель выполнения. Дождавшись выхода команды, вы работаете синхронно.

Возможно, вы можете разделить команды на три части: FooCommand1, которая выполняется до отправки BarCommand, BarCommand и, наконец, FooCommand2, которая продолжается после завершения BarCommand. Эти три команды могут быть поставлены в очередь отдельно. Конечно, BarCommand должен убедиться, что FooCommand2 находится в очереди.

1 голос
/ 24 сентября 2008

Я предполагаю, что вы хотите поставить BarCommand в очередь, чтобы он мог работать параллельно с FooCommand, но результат BarCommand понадобится позже. Если это так, то я бы порекомендовал использовать Future из библиотеки Parallel Extensions.

Bart DeSmet имеет хорошую запись в блоге об этом. В основном вы хотите сделать:


public void FooCommand()
{
    Future<int> BarFuture = new Future<int>( () => BarCommand() );

    // Do Foo's Processing - Bar will (may) be running in parallel

    int barResult = BarFuture.Value;

    // More processing that needs barResult
}

С такими библиотеками, как Parallel Extensions, я бы избегал "накатывать свои собственные" расписания.

1 голос
/ 24 сентября 2008

Если вы создаете объект Queue самостоятельно, вы можете попробовать несколько вещей:

  1. Динамически добавлять новые служебные потоки. Используйте таймер и добавьте поток, если число доступных потоков слишком долго было равно нулю.
  2. Если команда пытается поставить в очередь другую команду и ждать результата, вам следует синхронно выполнить вторую команду в том же потоке. Если первый поток просто ждет второго, вы все равно не получите преимущества от параллелизма.
1 голос
/ 24 сентября 2008

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

Обычно каждые N секунд проверяют, завершено ли какое-либо задание, если нет, добавьте еще один поток.

Это не обязательно решит еще более сложные проблемы взаимоблокировки, но решит эту.

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

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