![]() |
|
Модераторы: Daevaorn |
![]()
|
|
| mr.DUDA |
|
||||
|
3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 25 Всего: 232 |
Народ, кто-нибудь уже делал многопоточные приложения ?
Нужно написать класс типа:
т.е. так, чтобы объекты классов, производных от CShareable можно было бы разделять между двумя и более потоками, например:
ЗЫ, может как-то можно сделать без мьютексов ? Или с критическими секциями (работают быстрее, чем мьютексы) ?? Это сообщение отредактировал(а) mr.DUDA - 27.8.2003, 12:07 -------------------- ![]() |
||||
|
|||||
| Fantasist |
|
||||||
|
Лентяй ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1517 Регистрация: 24.3.2002 Репутация: 4 Всего: 41 |
Обычно используются критические секции. Правда Lock с тайм-аутом не очень удобно делать. Однако можно замутить что-то типа:
Mutex'ы делать не удобно. Для каждего экземляра класса надо создать уникальный mutex, а значит уникальное имя. Опять же, создавать mutex при каждом Lock'e как-то не красиво и не удобно. И в Unlock его надо удалять, а не Release'ать. Однако наиболее интересна концепция Lock'ирующих указателей. Типа:
Оператор-> следит за тем, чтобы к объекту не обращались бы не заблокировав его вначале. Если не хочеться терять эффективность, то проверку можно окружить #ifdef _DEBUG ... #endif Применять просто:
Можно еще добавить operator T*. Тогда в этом указателе можно будет блокировать не только экземпляры классов, а вообще любые переменные. -------------------- Волны гасят ветер... |
||||||
|
|||||||
| mr.DUDA |
|
||||
|
3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 25 Всего: 232 |
Fantasist, спасибо за отличную идею с lock_ptr !!!
Пару вопросов (м.б. глупых): 1) а нельзя ли делать WaitForSingleObject для критических секций (внутри CRITICAL_SECTION есть интересная переменная LockSemaphore):
2) почему:
если не задать имя для объекта WinAPI при его создании (а передать NULL), то мьютекс будет без имени, но тоже в единственном экземпляре. Это сообщение отредактировал(а) mr.DUDA - 29.8.2003, 23:37 -------------------- ![]() |
||||
|
|||||
| Fantasist |
|
||||
|
Лентяй ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1517 Регистрация: 24.3.2002 Репутация: 4 Всего: 41 |
Не знаю. Никогда не пробывал. Попробуй - нам расскажешь.
Да это я ошибся. Думал по привычной схеме: синхронизация потоков через ownership handle'а объекта синхронизации с помощью явных функций захвата владения и освобождения (критические секции), а mutex'ы используем как глобальный именованный синхронизатор. Для меня mutex'ы без имени были бесполезны. Поэтому твою схему сразу и не понял. -------------------- Волны гасят ветер... |
||||
|
|||||
| Ars |
|
||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 325 Регистрация: 28.8.2003 Где: Московская обл. Репутация: 2 Всего: 2 |
Весьма удобно использовать следующее:
Позволяет использовать несколько CriticalSection и не париться с обработкой exception:
-------------------- Есть многое на свете, друг Горацио, С чем очень долго можно прое..! |
||||
|
|||||
| mr.DUDA |
|
|||
|
3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 25 Всего: 232 |
У меня есть несколько вопросов, Ars и Fantasist:
1) сколько таких объектов можно создавать (если в каждом - хотя бы по одной критической секции) с точки зрения WinAPI, т.е. не запарится ли винда держать в памяти тысячу проинициализированных критических секций (если учесть, что под каждую выделяется не просто кусок памяти, а еще и семафор - объект ядра) 2) как долго выполняется InitializeCriticalSection/DeleteCriticalSection, и не уйдет ли всё процессорное время только на операции с крит. секциями (если ставить на все объекты, используемые в программе, защиту потоков). В моей проге возможен одновременный доступ нескольких потоков к любому объекту (а их может существовать от сотни до тысячи - как мелких, так и толстых) 3) чем круче критическая секция обычного мьютекса (если в крит. секции также используются объекты ядра - семафоры, и ожидающие функции - WaitForSingleObject), тем более что в критическую секцию можно попробовать войти, но нельзя дождаться её освобождения (выхода др. потока из неё) в течение определенного интервала. ЗЫ, Fantasist, можно конечно
и так делать, но не проще ли мьютекс+WaitForSingleObject ? Или есть какая-то другая причина для использования только критических секций ? Нужно определиться, что именно выгоднее в данной ситуации (когда критично время выполнения и корректность работы с кучей объектов). ЗЫ(2), я пробовал с семафором внутри CRITICAL_SECTION - что-то не получается. Винда как-то хитро его использует. Это сообщение отредактировал(а) mr.DUDA - 3.9.2003, 12:11 -------------------- ![]() |
|||
|
||||
| Ars |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 325 Регистрация: 28.8.2003 Где: Московская обл. Репутация: 2 Всего: 2 |
1. Думаю, ограничения могут быть связаны только с максимальным количеством системных объектов, поэтому пока создаются - можно создавать...
2. В проге чаще выполняются не InitializeCriticalSection/DeleteCriticalSection, а EnterCriticalSection/LeaveCriticalSection (т.к. все объекты должны использовать одни и те же CriticalSection). У потока при ожидании накладные расходы минимальны. 3. В хелпе написано:
К тому же, в critical section реализован механизм предотвращения deadlock'ов при повторном входе потока в одну и ту же critical section. Может так и у mutex'ов? Не проверял. А Билли Гейтс запретил лазить в CRITICAL_SECTION. Говорит, что она only для системного использования P.S. IMHO для работы с большим количеством объектов лучше не перегружать объекты операциями синхронизации, а сделать менеджер объектов, который возьмет на себя эти функции. Это сообщение отредактировал(а) Ars - 3.9.2003, 14:10 -------------------- Есть многое на свете, друг Горацио, С чем очень долго можно прое..! |
|||
|
||||
| Ars |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 325 Регистрация: 28.8.2003 Где: Московская обл. Репутация: 2 Всего: 2 |
mr.DUDA, прошу прощения. Из-за узости мышления не совсем въехал в суть и допустил несколько неточностей...
Для решения твоей задачи надо разобраться с несколькими вопросами: 1. Что необходимо синхронизировать - доступ к многочисленным объектам или к данным этих объектов? 2. Как долго выполняется код между вызовами Lock и Unlock? Некоторые соображения: Если необходимо синхронизировать доступ к объектам или их данным и обращения к ним носят характер чтения-записи (без длительной обработки), то с этим вполне может справиться менеджер объектов, используя только один синхро-объект по схеме: а) залочить список объектов; б) создать или удалить объект, прочитать или записать его данные; в) разлочить список объектов. Если есть длительная обработка, то может ее можно вынести в отдельный поток со всеми данными для нее? Ну а если все до кучи - видимо без синхро-объекта в каждом экземпляре класса не обойтись, но я с такими несчастными случаями не сталкивался. Вообще, во многих случаях можно обойтись следующим кодом. Грубо, но ни разу не глючило.
-------------------- Есть многое на свете, друг Горацио, С чем очень долго можно прое..! |
|||
|
||||
| Fantasist |
|
||||||
|
Лентяй ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1517 Регистрация: 24.3.2002 Репутация: 4 Всего: 41 |
В этом случае полезно подумать, а нельзя ли разбить объекты на функционально связанные группы и блокировать сразу группами. Типа транзакции.
Конечно, с mutex'ами также. С какой-то стороны они даже безопаснее, ибо в reference есть такое упоминание:
Про mutex'ов такого нет. Конечно, такая ситуация может возникнуть только в запутанной системе управления синхронизацией. На практике я не видел ничего близкого к подобной ситуации. И тем не менее. -------------------- Волны гасят ветер... |
||||||
|
|||||||
| mr.DUDA |
|
|||
|
3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 25 Всего: 232 |
to Ars:
1) к данным любого объекта м.б. предоставлен доступ на чтение и запись, из любого потока 2) объекты упорядочены по иерархии (каждый объект имеет 2 списка дочерних объектов) 3) объектов м.б. очень много, и структура м.б. очень сложной 4) обработка данных объекта может занять определенное время (если например используются файловые или оконные функции для сохранения/чтения или отображения объекта) имхо, можно было бы сделать внутри каждого потока свою CRITICAL_SECTION, и в каждом объекте хранить указатель на CRITICAL_SECTION потока-владельца (тогда любой другой поток сначала подождет полного освобождения критической секции, прежде чем писать или читать объект). Только недостаток этого подхода в том, что если скажем мы заблокировали одним потоком доступ сначала к объекту X, а потом - к объекту Y, то другой поток не сможет получить доступа к объекту X, пока не будет полностью освобождена критическая секция (т.е. нужно освободить доступ как к X, так и к Y). С другой стороны, хранить внутри каждого объекта мьютекс или критическую секцию невыгодно. Менеджер объектов даст только лишнюю головную боль. -------------------- ![]() |
|||
|
||||
| Ars |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 325 Регистрация: 28.8.2003 Где: Московская обл. Репутация: 2 Всего: 2 |
mr.DUDA, да-а-а!..
Все равно, в жизни нет истинной многозадачности, ибо кол-во процессоров много меньше кол-ва потоков и какая разница, будет ли поток простаивать в ожидании освобождения сихронизирующего объекта или в ожидании своего процессорного времени. Поэтому, если время однократного прохода по трид-защищенному коду сравнимо с несколькими квантами времени для этого потока, то не стоит напрягаться по поводу блокировки сразу всех объектов на входе в суперструктуру и использовать один сихронизирующий объект. Для продолжительной обработки данных вполне подходит отдельный поток или асинхронные функции (что, в принципе, одно и то же). IMHO, вообще, грамотно разделять обработку данных на процессоре и медленный ввод-вывод. Не совсем понял идею
CRITICAL_SECTION - это как раз то, что у них должно быть общее. Как они будут подменять указатель на CRITICAL_SECTION в объекте? Что будет делать поток-владелец, когда его CRITICAL_SECTION поимеют другие (потоки), т.е. как он вернет ее себе? И вот еще. Стремно делать CRITICAL_SECTION (или другой синхрообъект с бесконечным ожиданием) в каждом объекте, если планируется залочивать более одного объекта одновременно, т.к. легко словить взаимную блокировку потоков. -------------------- Есть многое на свете, друг Горацио, С чем очень долго можно прое..! |
|||
|
||||
| mr.DUDA |
|
|||
|
3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 25 Всего: 232 |
А если забить на многопотоковую модель и сделать 1 поток для выполнения списка действий ? А еще можно сделать 2-й поток, извлекающий из очереди сообщения одно за другим и посылающий их второму потоку-исполнителю; в случае "подвисания" второго потока, первый после таймаута перезапустит его.
Так можно снять вообще проблему разделения объектов несколькими потоками. Суть решаемой проблемы - сделать возможной обработку т.н. "сообщений" (задаваемых числовым ID'ом и списком параметров) с "завёрткой" в тело сообщения указателей на объекты из общего для всех потоков дерева объектов. Для расширяемого (с пом. модулей) приложения нужно выбрать способ реакции внутри каждого модуля на "приходящее" в очередь сообщение: либо делать внутри каждого DLL свой поток обработки сообщений, либо делать внутри "главного модуля" (EXE-шки) один единственный поток (или 2, описанных выше), и при загрузке модуля регистрировать сообщения данного модуля так, чтобы при поступлении сообщения MSG_A вызывалась ф-ция из модуля MOD_A. Дерево объектов общее, т.к. собственно решается задача совместной работы множества подключаемых модулей над одним объектом-"документом". -------------------- ![]() |
|||
|
||||
| Ars |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 325 Регистрация: 28.8.2003 Где: Московская обл. Репутация: 2 Всего: 2 |
mr.DUDA, если это еще актуально, скинь мне на личку пересказ ТЗ в части описания пользователей (и/или внешних систем), их количества и их требований к скорости доступа к объектам. Подумаю на досуге...
-------------------- Есть многое на свете, друг Горацио, С чем очень долго можно прое..! |
|||
|
||||
![]()
|
| Правила форума "С++:Общие вопросы" | |
|
|
Добро пожаловать!
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | C/C++: Общие вопросы | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |