Название: QSharedMemory QReadWriteLock Отправлено: ammaximus от Ноябрь 02, 2014, 12:52 По не зависящим от меня причинам необходимо использовать ряд процессов, которые используют общую память. Как правило при этом изменяет содержимое памяти лишь один из них, а остальные являются читателями.
Возможно ли в этом случае использовать механизм, аналогичный QReadWriteLock и как? Насколько я понял, QSharedMemory::lock() - это монопольный мутекс на использование памяти, QSystemSemaphore тоже не помогли. Может запихать объект QReadWriteLock в SharedMemory, но будет ли в этом смысл? Название: Re: QSharedMemory QReadWriteLock Отправлено: Igors от Ноябрь 02, 2014, 13:40 QReadWriteLock никакого отношения к шаред памяти не имеет. Вам нужно QSharedMemory + QSystemSemaphore. После того как процесс записал данные в общую память он сообщает др процессам что данные готовы (QSystemSemaphore) - ну дальше разберетесь
Название: Re: QSharedMemory QReadWriteLock Отправлено: ammaximus от Ноябрь 02, 2014, 15:39 Значит я не понял как пользоваться QSystemSemaphore. Можно в двух словах применительно к этой задаче? То есть понятно как сделать с его помощью блокирующий вызов, а как сделать аналог QReadWriteLock. Чтобы пишущий процесс вставал в приоритетную очередь, иначе возможно, что он вообще никогда не сможет дождаться записи, поскольку читателей очень много.
Название: Re: QSharedMemory QReadWriteLock Отправлено: Igors от Ноябрь 02, 2014, 20:12 .., а как сделать аналог QReadWriteLock. Чтобы пишущий процесс вставал в приоритетную очередь, иначе возможно, что он вообще никогда не сможет дождаться записи, поскольку читателей очень много. Хмм... уточните как читатели читают если их много? Не получится ли что двое одно и то же прочитали? В двух словах так: писатель взводит флажок (напр pending_write) в шаред памяти и ждет пока счетчик читателей num_readers (там же в шаред) обнулится. Увидев pending_write != 0 новый читатель не должен пытаться читать и увеличивать num_readers, Название: Re: QSharedMemory QReadWriteLock Отправлено: vulko от Ноябрь 02, 2014, 20:58 Если читателей много и 1 писатель, используй ReadWriteLock.
Он не должен быть в расшаренной памяти, сам объект лишь позволяет разделять доступ. Т.е. если один поток захватил на запись, другой не сможет этого сделать пока первый не закончит. Название: Re: QSharedMemory QReadWriteLock Отправлено: ammaximus от Ноябрь 03, 2014, 01:27 Есть один процесс, который иногда обновляет общую память по приходу из канала. Есть несколько процессов, которые периодически лазают в общую память и читают ее содержимое. Их интересует только текущее состояние памяти.
Igors: pending_write - это QSystemSemaphore? Т.е. к каждому сегменту общей памяти нужно приставить два семафора. (по сути один для учета читателей, а pending_write будет работать через встроенный QSharedMemory.lock()). Это вариант, попробую. vulko: Если не положить QReadWriteLock в QSharedMemory, то он не будет доступен из другого процесса. А если положить, то я во-первых не знаю будет ли он там работать, а во-вторых разделяемая память выделяется только для объектов постоянного размера имеющих постоянный адрес в памяти. И мне не известно как поведет себя в таком случае QReadWriteLock. Вообще, я сейчас из-за этого как раз и огребаю: мне нужна функциональность QVector, но QVector - это динамическая структура, которая любит расширятся и, что самое классное, внезапно полностью копировать себя в новый участок памяти, что в разделяемой памяти в лучшем случае приведет к segfault. Поэтому я сейчас пишу свой вектор (шаблон), который получает в параметре максимальный размер (для моей задачи это допустимо) и выделяет разделяемую память T*maxsize. После этого я гарантирую, что не выйду за пределы памяти. Но уже после первого дня работы я несколько раз огреб на классических ошибках в арифметике указателей. Поэтому мне так не хочется изобретать велосипеды - ни вектора, ни QRWL, поскольку это системная область и ошибки в ней очень трудно ловятся. Название: Re: QSharedMemory QReadWriteLock Отправлено: Igors от Ноябрь 03, 2014, 10:35 pending_write - это QSystemSemaphore? Т.е. к каждому сегменту общей памяти нужно приставить два семафора. (по сути один для учета читателей, а pending_write будет работать через встроенный QSharedMemory.lock()). Это вариант, попробую. Там не так просто. Я обдумаю и отпишусь. Можно ли хранить классы в шаред памяти - ну как минимум new/delete не будет нормально работать, и этого достаточно чтобы не искать таких приключений :)Название: Re: QSharedMemory QReadWriteLock Отправлено: Igors от Ноябрь 03, 2014, 11:38 Аттач
Название: Re: QSharedMemory QReadWriteLock Отправлено: ammaximus от Ноябрь 03, 2014, 15:19 Код: QAtomicInt Сам бы не догадался) Все действительно непросто, буду разбираться, спасибо. Название: Re: QSharedMemory QReadWriteLock Отправлено: Авварон от Ноябрь 03, 2014, 16:07 Есть один процесс, который иногда обновляет общую память по приходу из канала. Есть несколько процессов, которые периодически лазают в общую память и читают ее содержимое. Их интересует только текущее состояние памяти. Igors: pending_write - это QSystemSemaphore? Т.е. к каждому сегменту общей памяти нужно приставить два семафора. (по сути один для учета читателей, а pending_write будет работать через встроенный QSharedMemory.lock()). Это вариант, попробую. vulko: Если не положить QReadWriteLock в QSharedMemory, то он не будет доступен из другого процесса. А если положить, то я во-первых не знаю будет ли он там работать, а во-вторых разделяемая память выделяется только для объектов постоянного размера имеющих постоянный адрес в памяти. И мне не известно как поведет себя в таком случае QReadWriteLock. Вообще, я сейчас из-за этого как раз и огребаю: мне нужна функциональность QVector, но QVector - это динамическая структура, которая любит расширятся и, что самое классное, внезапно полностью копировать себя в новый участок памяти, что в разделяемой памяти в лучшем случае приведет к segfault. Поэтому я сейчас пишу свой вектор (шаблон), который получает в параметре максимальный размер (для моей задачи это допустимо) и выделяет разделяемую память T*maxsize. После этого я гарантирую, что не выйду за пределы памяти. Но уже после первого дня работы я несколько раз огреб на классических ошибках в арифметике указателей. Поэтому мне так не хочется изобретать велосипеды - ни вектора, ни QRWL, поскольку это системная область и ошибки в ней очень трудно ловятся. используйте std::vector, у него можно задавать свой аллокатор. Как это делать - в гугл( Название: Re: QSharedMemory QReadWriteLock Отправлено: Igors от Ноябрь 03, 2014, 16:25 используйте std::vector, у него можно задавать свой аллокатор. Как это делать - в гугл( Еще один фанат вектора :) Я бы не связывался, если в шаред требуется что-то выше POD структур - сериализовать и все дела. Название: Re: QSharedMemory QReadWriteLock Отправлено: vulko от Ноябрь 05, 2014, 09:24 Есть один процесс, который иногда обновляет общую память по приходу из канала. Есть несколько процессов, которые периодически лазают в общую память и читают ее содержимое. Их интересует только текущее состояние памяти. vulko: Если не положить QReadWriteLock в QSharedMemory, то он не будет доступен из другого процесса. А если положить, то я во-первых не знаю будет ли он там работать, а во-вторых разделяемая память выделяется только для объектов постоянного размера имеющих постоянный адрес в памяти. И мне не известно как поведет себя в таком случае QReadWriteLock. Вообще, я сейчас из-за этого как раз и огребаю: мне нужна функциональность QVector, но QVector - это динамическая структура, которая любит расширятся и, что самое классное, внезапно полностью копировать себя в новый участок памяти, что в разделяемой памяти в лучшем случае приведет к segfault. Поэтому я сейчас пишу свой вектор (шаблон), который получает в параметре максимальный размер (для моей задачи это допустимо) и выделяет разделяемую память T*maxsize. После этого я гарантирую, что не выйду за пределы памяти. Но уже после первого дня работы я несколько раз огреб на классических ошибках в арифметике указателей. Поэтому мне так не хочется изобретать велосипеды - ни вектора, ни QRWL, поскольку это системная область и ошибки в ней очень трудно ловятся. Понятно. А обязательно должны быть процессы? Переделать на потоки нельзя? Название: Re: QSharedMemory QReadWriteLock Отправлено: ammaximus от Ноябрь 05, 2014, 14:31 Да, такое условие. Решается задача повышения надежности - есть процесс-родитель (диспетчер) он следит за состоянием процессов и восстанавливает их в случае вылета. Не знаю, насколько этот подход правильный, но пока менять его не будем.
Название: Re: QSharedMemory QReadWriteLock Отправлено: ammaximus от Ноябрь 06, 2014, 09:57 1. Забыл указать, у меня Qt4.8, там нет QAtomicInt::load(). Насколько это критично?
2. Не совсем понял, что происходит здесь: Код: if (dst.testAndSetOrdered(cur, val)) Код: if (!BeginWrite(data->mCount)) Если нет активных читателей мы пропускаем захват семафора, но сразу делаем lock? Название: Re: QSharedMemory QReadWriteLock Отправлено: Igors от Ноябрь 06, 2014, 11:01 1. Забыл указать, у меня Qt4.8, там нет QAtomicInt::load(). Насколько это критично? Тогда замените на просто присваивание, напр cur = dst 2. Не совсем понял, что происходит здесь: В любом случае мы увеличиваем число писателей. Если на этот момент не было активных читателей - писатель сразу идет писать, иначе ждет на семафоре пока последний отчитавшийся его не откроет. В общем случае неск писателей могут прорваться на запись, поэтому по записи надо делать lock/unlock (а вот по чтению нет).Код: if (dst.testAndSetOrdered(cur, val)) Код: if (!BeginWrite(data->mCount)) Если нет активных читателей мы пропускаем захват семафора, но сразу делаем lock? Название: Re: QSharedMemory QReadWriteLock Отправлено: vulko от Ноябрь 06, 2014, 12:08 Да, такое условие. Решается задача повышения надежности - есть процесс-родитель (диспетчер) он следит за состоянием процессов и восстанавливает их в случае вылета. Не знаю, насколько этот подход правильный, но пока менять его не будем. интересный подход к надежности...))) Название: Re: QSharedMemory QReadWriteLock Отправлено: ammaximus от Ноябрь 06, 2014, 13:16 Цитировать интересный подход к надежности...))) Каждый процесс связан с отдельным внешним устройством, которые могут повести себя неадекватно и всего не предусмотришь. Поэтому отказ одного модуля не должен приводить к краху системы в целом. Я предлагал многопоточную реализацию, но у нас что-то присосались к этой системе и изменить это не выходит. Там нюанс в том, что любой процесс может находится на любой машине в пределах локальной сети и он общается с другими через сокет. Пока допилю это, потом будем искать лучшее решение. Название: Re: QSharedMemory QReadWriteLock Отправлено: vulko от Ноябрь 06, 2014, 13:20 Цитировать интересный подход к надежности...))) Каждый процесс связан с отдельным внешним устройством, которые могут повести себя неадекватно и всего не предусмотришь. Поэтому отказ одного модуля не должен приводить к краху системы в целом. Я предлагал многопоточную реализацию, но у нас что-то присосались к этой системе и изменить это не выходит. Там нюанс в том, что любой процесс может находится на любой машине в пределах локальной сети и он общается с другими через сокет. Пока допилю это, потом будем искать лучшее решение. ну если данных не так много, то можно и сокеты. а вообще многопоточное решение вполне рабочее, то что устройства могут повести себя неадекватно, можно в общем то предусмотреть, чтобы потоки не отваливались... но это если производительности через сокеты не хватит. мне кажется по локалке вполне будет достаточно. Название: Re: QSharedMemory QReadWriteLock Отправлено: Igors от Ноябрь 06, 2014, 13:29 Я предлагал многопоточную реализацию, но у нас что-то присосались к этой системе и изменить это не выходит. Не раз видел обратную ситуацию (хотят процессы вместо потоков). Процесс можно прибить, а вот поток нетНазвание: Re: QSharedMemory QReadWriteLock Отправлено: ammaximus от Ноябрь 06, 2014, 18:13 Есть у процессов некое преимущество, и даже их медлительность при переключении для нас не критична. Меня лишь огорчает необходимость изобретать велосипеды. Сегодня весь день убил на аналог вектора с форычем и еще не факт, что все правильно.
Название: Re: QSharedMemory QReadWriteLock Отправлено: Old от Ноябрь 06, 2014, 18:42 и даже их медлительность при переключении для нас не критична. Нет у них никакой медлительности.В linux процессы переключаются с той же скоростью, что и потоки. Точнее потоки в linux, это те-же процессы, которые делят одно адресное пространство. И подход с процессами правильный, в дальнейшем вы много полезного сможете получить. Название: Re: QSharedMemory QReadWriteLock Отправлено: VPS от Ноябрь 06, 2014, 20:11 Сегодня весь день убил на аналог вектора с форычем и еще не факт, что все правильно. Вроде как библиотека Boost.Interprocess имеет свои реализации контейнеров для использования их в разделяемой памяти. Название: Re: QSharedMemory QReadWriteLock Отправлено: ammaximus от Ноябрь 06, 2014, 23:36 Цитировать И подход с процессами правильный, в дальнейшем вы много полезного сможете получить. Спасибо, очень хотел услышать подобное))Цитировать Вроде как библиотека Boost.Interprocess имеет свои реализации контейнеров для использования их в разделяемой памяти. Уже выбрана Qt, придется обойтись ее средствами. Но я подгляжу как там у них)Название: Re: QSharedMemory QReadWriteLock Отправлено: Igors от Ноябрь 07, 2014, 11:04 Меня лишь огорчает необходимость изобретать велосипеды. Сегодня весь день убил на аналог вектора с форычем и еще не факт, что все правильно. А нужны ли такие хитрости? Можно держать в шаред простые массивы, напр "счетчик" и дальше следуют элементы. Что-то более сложное - сериализовать. При обращении к шаред прочитать данные (де-сериализовать), сразу же освободить шаред, и потом, в "своей" памяти, спокойно разбираться. Если массив(ы) трудно зарезервировать по максимуму, то создавать для него новый (отдельный) шаред блок при перезаписи. |