Отслеживание статусов экземпляров объектов в разных потоках? - PullRequest
0 голосов
/ 03 апреля 2011

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

Сейчас у меня есть «процессоры очередей», которые наблюдают и работают с определенными типами потоково-безопасных очередей.Эти обработчики очереди опрашивают целевую очередь каждые X секунд, и, если в очереди есть элемент, ожидающий обработки, процессор очереди удаляет из очереди этот элемент, запускает новый поток с этим элементом и запускает поток.В каждом потоке вызываются долгосрочные методы (например, подключение к веб-сайту и загрузка файла).Таким образом, каждый элемент получает свой собственный поток для выполнения.

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

Например, допустим, у нас есть основной поток MT.MT порождает дочерние потоки T1, T2, T3, T4 и T5.На каждом потоке есть соответствующий объект, O1 ... O5.Эти объекты могут находиться, скажем, в трех разных состояниях - S1, S2, S3 - пока он обрабатывается в его потоке.

Как я могу сообщить о состоянии S каждого объекта O в основной поток MTкогда состояние объекта O изменяется?

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

Любая помощь будет признательна.

Спасибо.

1 Ответ

1 голос
/ 03 апреля 2011

Один из способов сделать это - создать другую потокобезопасную очередь, которая будет использоваться для сообщения об обновлениях состояния.Каждый раз, когда ваш поток меняет свой статус, он выдвигает кортеж / объект, содержащий уникальный идентификатор работы, новый статус, идентификатор потока и все, что вы считаете необходимым.

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

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

Вот некоторый псевдокод, иллюстрирующий концепцию:

main_thread()
    ...
    thread_pool = create_pool(get_core_count());
    thread_pool.execute(worker_thread);

    while(true)
         status = status_queue.pop_blocking();
         if (check_status(status) == WE_BE_DONE) 
             break;

    thread_pool.interrupt();
    ...

worker_thread()
    while(true)
        job = job_queue.pop_blocking();
        process_job(job);
        status_queue.push({job.id, thread_id, WE_DONE});

По сути, это создает пул потоков, который содержит один рабочий поток на каждое ядро ​​процессора (нормально по умолчанию для запускас).Затем он выполняет функцию worker_thread в каждом рабочем потоке (функция должна быть понятной).Затем основной поток постоянно проверяет очередь состояния на наличие определенного неопределенного события.Как только это происходит, он убивает рабочие потоки и возобновляет выполнение остальной части программы.

Три вещи, на которые стоит обратить внимание в примере.Прежде всего, я рекомендую использовать блокирующий всплывающий вызов (pop_blocking в примере) вместо реализации опроса вручную.Это намного проще в использовании и, возможно, гораздо эффективнее.Затем я использовал thread_pool.interrupt(), чтобы уничтожить потоки заданий, но это может быть не самый умный способ сделать это в зависимости от языка или библиотеки, которую вы используете.Возможно, это также хорошая идея заключить вызов do_job(job) в оператор try catch, если ваш язык поддерживает такие вещи.

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

...