Название: [РЕШЕНО] OpenMP и деление дерева Отправлено: Igors от Март 05, 2010, 14:29 Добрый день
Использую OpenMP и весьма доволен этой библиотекой. Не могу сообразить как мне распараллелить деление дерева, алгоритм стандартный: - Есть очередь нодов, (вначале только с 1 нодом). - Извлекаем первый нод из очереди, делим его на 2 нода - Подсчитываем приоритеты получившихся нодов, и, если надо, добавляем их в очередь - Опять извлекаем первый нод (нод с наивысшим приоритетом) из очереди и.т.д Нод хранит список примитивов которые его пересекают. Приоритет вычисляется как число примитивов в ноде помноженное на его размер. Все работает. Теперь как задействовать N ниток? Понятно что помещение в очередь и извлечение из нее должны быть защищены блокировками. Возможна ситуация когда очередь пуста, но это не значит "конец расчета" - нод(ы) делятся в др. нитках. Как бы мне это все организовать попроще и покрасивее? Спасибо Название: Re: OpenMP и деление дерева Отправлено: BlackTass от Март 07, 2010, 01:05 бери в качестве условия окончания не просто опустошение очереди, а опустошение очереди и законченную работу всех потоков
Название: Re: OpenMP и деление дерева Отправлено: Igors от Март 07, 2010, 14:33 бери в качестве условия окончания не просто опустошение очереди, а опустошение очереди и законченную работу всех потоков Не очень понятно, что такое "законченная работа всех потоков" :) Ведь пока хоть один нод делится - ни одну нитку мне заканчивать не резон.Название: Re: OpenMP и деление дерева Отправлено: Авварон от Март 07, 2010, 22:34 дык семафор. Начинаем работу, +1. Стопаемся -1. Когда 0 выходим.
Название: Re: OpenMP и деление дерева Отправлено: Igors от Март 08, 2010, 00:57 дык семафор. Начинаем работу, +1. Стопаемся -1. Когда 0 выходим. Мне это тоже казалось простым :) Вот псевдокод для одно-ниточной версии. Для простоты полагаем что все ф-ции thread-safe (потокобезопасны). Прошу показать как сделать +1 и -1.Код: void DivideTree( void ) Название: Re: OpenMP и деление дерева Отправлено: Авварон от Март 09, 2010, 10:14 Код: void DivideTree( void ) надеюсь я не ошибся Название: Re: OpenMP и деление дерева Отправлено: Igors от Март 09, 2010, 13:48 Полагаем что sem++, sem--, sem.wait_for_zero есть атомарные операции, защищенные мутексом или др. блокировкой.
Рассмотрим ситуацию для 2-х ниток Код: void DivideTree( void ) Название: Re: OpenMP и деление дерева Отправлено: Авварон от Март 09, 2010, 13:56 тогда инициализируй семафор количеством ниток перед входом в параллельную область
ща подумаю как оно надо. В общем ты прав, проблемы будут на переходах между изменениями значения и проверками. Хорошо бы это дело замьютексить, но проще будет написать свой семафор added: все равно фигня получается... видимо мьютексы, мьютексы и еще раз мьютексы:( Название: Re: OpenMP и деление дерева Отправлено: Igors от Март 09, 2010, 17:32 added: все равно фигня получается... видимо мьютексы, мьютексы и еще раз мьютексы:( Не расстраивайтесь, это действительно трудно. Я сделал вариант, работает прилично, но все же иногда нитки крутятся вхолостую. Вот "принципиальная схема" (как это называлось в мое время)Код: void DivideTree( void ) Название: Re: OpenMP и деление дерева Отправлено: Авварон от Март 09, 2010, 21:46 ну в данном варианте очень много while(1) крутится, пока мы ожидаем новых нодов. Я пытался этого избежать таймаутом.
Название: Re: OpenMP и деление дерева Отправлено: Igors от Март 10, 2010, 11:38 ну в данном варианте очень много while(1) крутится, пока мы ожидаем новых нодов. Согласен и я избегаю большинства таких прокруток (хотя и не всех): если после взятия нода очередь пуста - то делать UNLOCK_TREE не сразу а в конце цикла. Это заставляет остальные нитки ждать на первом LOCK_TREE т.к. все равно им нечего делать пока данная нитка не создаст новые ноды. К сожалению, текст получается очень навороченный и приводить его нет смысла.Название: Re: OpenMP и деление дерева Отправлено: spectre71 от Май 02, 2010, 13:14 Более простой пример с семафором.
Нет никаких лишних блокировок и прокруток цикла! Привожу пример на QSemaphore, легко переделать на нативный. Код: QSemaphore sem(1); //изначально имеем 1 ноду Название: Re: OpenMP и деление дерева Отправлено: spectre71 от Май 02, 2010, 13:46 Ошибся! :)
В итоге(когда список опустеет) все потоки встанут на семафор. Надо еще подумать. Название: Re: OpenMP и деление дерева Отправлено: Igors от Май 02, 2010, 13:49 Более простой пример с семафором. Пример: имеем 1 нод. Поделили его, оба "осколка" оказались малы (IsNodeBig вернула false). Все нитки ждут на семафоре forever :) Нет никаких лишних блокировок и прокруток цикла! Edit: опоздал - отправил, и только потом увидел Ваш новый ответ :) Название: Re: OpenMP и деление дерева Отправлено: spectre71 от Май 02, 2010, 16:26 Вроде так правильно.
GetNodeCount - возвращает текущее кол-во нод в списке GetNodeCount, GetNodeFromTree, AddNodeToTree. Защищать внутри не требуется! Код: QSemaphore sem(1); //изначально имеем 1 ноду Название: Re: OpenMP и деление дерева Отправлено: Igors от Май 02, 2010, 18:51 - нитка 1 занимается делением (DivideNode)
- нитка 2 ждет на семафоре Деление закончено, новый нод добавлен, счетчик семафора = 1. Но ведь нет никаких гарантий, что после этого именно нитка 2 снимется с семафора и захватит мутекс. Это может быть опять нитка 1, которая продолжает крутить свой while. Пусть нитка 1 опять захватила мутекс. Тогда если нитка 2 успела сняться с семафора, она ждет на мутексе (захваченном ниткой 1). А нитка 1 (ведь есть ноды для деления) отправляется ждать на семафоре, закрытом ниткой 2. Имеем deadlock Название: Re: OpenMP и деление дерева Отправлено: spectre71 от Май 02, 2010, 19:08 - нитка 1 занимается делением (DivideNode) - нитка 2 ждет на семафоре Деление закончено, новый нод добавлен, счетчик семафора = 1. Но ведь нет никаких гарантий, что после этого именно нитка 2 снимется с семафора и захватит мутекс. Это может быть опять нитка 1, которая продолжает крутить свой while. Пусть нитка 1 опять захватила мутекс. Тогда если нитка 2 успела сняться с семафора, она ждет на мутексе (захваченном ниткой 1). А нитка 1 (ведь есть ноды для деления) отправляется ждать на семафоре, закрытом ниткой 2. Имеем deadlock Не имеем. Поскольку перед попаданием на семафор нитка 1 разблокирует мутекс: if(!sem.tryAcquire()) { if(!ActiveThreadCount && !GetNodeCount()) { locker.unlock(); sem.release(); break; } else { locker.unlock(); // нитка 1 разблокирует мутекс и только после этого попадает на семафор sem.acquire(); locker.lock(); // нитка 2 снялясь с семафора ждет на мутексе } } Название: Re: [РЕШЕНО] OpenMP и деление дерева Отправлено: Igors от Май 03, 2010, 00:08 locker.unlock(); // нитка 1 разблокирует мутекс и только после этого попадает на семафор Убедили :) Помечаю как "решено". Реализация правда не блещет (lock на мутексе + tryAcquire + acquire) но это не принципиально sem.acquire(); |