Russian Qt Forum
Ноябрь 23, 2024, 03:03 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: QSharedMemory QReadWriteLock  (Прочитано 12626 раз)
ammaximus
Гость
« : Ноябрь 02, 2014, 12:52 »

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

Возможно ли в этом случае использовать механизм, аналогичный QReadWriteLock и как?

Насколько я понял, QSharedMemory::lock()  - это монопольный мутекс на использование памяти, QSystemSemaphore тоже не помогли.

Может запихать объект QReadWriteLock в SharedMemory, но будет ли в этом смысл?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Ноябрь 02, 2014, 13:40 »

QReadWriteLock никакого отношения к шаред памяти не имеет. Вам нужно QSharedMemory + QSystemSemaphore. После того как процесс записал данные в общую память он сообщает др процессам что данные готовы (QSystemSemaphore) - ну дальше разберетесь
Записан
ammaximus
Гость
« Ответ #2 : Ноябрь 02, 2014, 15:39 »

Значит я не понял как пользоваться QSystemSemaphore. Можно в двух словах применительно к этой задаче? То есть понятно как сделать с его помощью блокирующий вызов, а как сделать аналог QReadWriteLock. Чтобы пишущий процесс вставал в приоритетную очередь, иначе возможно, что  он вообще никогда не сможет дождаться записи, поскольку читателей очень много.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Ноябрь 02, 2014, 20:12 »

.., а как сделать аналог QReadWriteLock. Чтобы пишущий процесс вставал в приоритетную очередь, иначе возможно, что  он вообще никогда не сможет дождаться записи, поскольку читателей очень много.
Хмм... уточните как читатели читают если их много? Не получится ли что двое одно и то же прочитали?
В двух словах так: писатель взводит флажок (напр pending_write) в шаред памяти и ждет пока счетчик читателей num_readers (там же в шаред) обнулится. Увидев pending_write != 0 новый читатель не должен пытаться читать и увеличивать  num_readers, 
Записан
vulko
Гость
« Ответ #4 : Ноябрь 02, 2014, 20:58 »

Если читателей много и 1 писатель, используй ReadWriteLock.

Он не должен быть в расшаренной памяти, сам объект лишь позволяет разделять доступ. Т.е. если один поток захватил на запись, другой не сможет этого сделать пока первый не закончит.
Записан
ammaximus
Гость
« Ответ #5 : Ноябрь 03, 2014, 01:27 »

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

Igors:
pending_write - это QSystemSemaphore? Т.е. к каждому сегменту общей памяти нужно приставить два семафора. (по сути один для учета читателей, а pending_write будет работать через встроенный QSharedMemory.lock()). Это вариант, попробую.

vulko:
Если не положить QReadWriteLock в QSharedMemory, то он не будет доступен из другого процесса. А если положить, то я во-первых не знаю будет ли он там работать, а во-вторых разделяемая память выделяется только для объектов постоянного размера имеющих постоянный адрес в памяти. И мне не известно как поведет себя в таком случае QReadWriteLock.

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

Поэтому я сейчас пишу свой вектор (шаблон), который получает в параметре максимальный размер (для моей задачи это допустимо) и выделяет разделяемую память T*maxsize. После этого я гарантирую, что не выйду за пределы памяти.

Но уже после первого дня работы я несколько раз огреб на классических ошибках в арифметике указателей. Поэтому мне так не хочется изобретать велосипеды - ни вектора, ни QRWL, поскольку это системная область и ошибки в ней очень трудно ловятся.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Ноябрь 03, 2014, 10:35 »

pending_write - это QSystemSemaphore? Т.е. к каждому сегменту общей памяти нужно приставить два семафора. (по сути один для учета читателей, а pending_write будет работать через встроенный QSharedMemory.lock()). Это вариант, попробую.
Там не так просто. Я обдумаю и отпишусь. Можно ли хранить классы в шаред памяти - ну как минимум new/delete не будет нормально работать, и этого достаточно чтобы не искать таких приключений  Улыбающийся
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Ноябрь 03, 2014, 11:38 »

Аттач
Записан
ammaximus
Гость
« Ответ #8 : Ноябрь 03, 2014, 15:19 »

Код:
QAtomicInt

Сам бы не догадался) Все действительно непросто, буду разбираться, спасибо.
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #9 : Ноябрь 03, 2014, 16:07 »

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

Igors:
pending_write - это QSystemSemaphore? Т.е. к каждому сегменту общей памяти нужно приставить два семафора. (по сути один для учета читателей, а pending_write будет работать через встроенный QSharedMemory.lock()). Это вариант, попробую.

vulko:
Если не положить QReadWriteLock в QSharedMemory, то он не будет доступен из другого процесса. А если положить, то я во-первых не знаю будет ли он там работать, а во-вторых разделяемая память выделяется только для объектов постоянного размера имеющих постоянный адрес в памяти. И мне не известно как поведет себя в таком случае QReadWriteLock.

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

Поэтому я сейчас пишу свой вектор (шаблон), который получает в параметре максимальный размер (для моей задачи это допустимо) и выделяет разделяемую память T*maxsize. После этого я гарантирую, что не выйду за пределы памяти.

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

используйте std::vector, у него можно задавать свой аллокатор. Как это делать - в гугл(
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Ноябрь 03, 2014, 16:25 »

используйте std::vector, у него можно задавать свой аллокатор. Как это делать - в гугл(
Еще один фанат вектора Улыбающийся Я бы не связывался, если в шаред требуется что-то выше POD структур - сериализовать и все дела.
Записан
vulko
Гость
« Ответ #11 : Ноябрь 05, 2014, 09:24 »

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

vulko:
Если не положить QReadWriteLock в QSharedMemory, то он не будет доступен из другого процесса. А если положить, то я во-первых не знаю будет ли он там работать, а во-вторых разделяемая память выделяется только для объектов постоянного размера имеющих постоянный адрес в памяти. И мне не известно как поведет себя в таком случае QReadWriteLock.

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

Поэтому я сейчас пишу свой вектор (шаблон), который получает в параметре максимальный размер (для моей задачи это допустимо) и выделяет разделяемую память T*maxsize. После этого я гарантирую, что не выйду за пределы памяти.

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

Понятно.
А обязательно должны быть процессы? Переделать на потоки нельзя?
Записан
ammaximus
Гость
« Ответ #12 : Ноябрь 05, 2014, 14:31 »

Да, такое условие. Решается задача повышения надежности - есть процесс-родитель (диспетчер) он следит за состоянием процессов и восстанавливает их в случае вылета. Не знаю, насколько этот подход правильный, но пока менять его не будем.
Записан
ammaximus
Гость
« Ответ #13 : Ноябрь 06, 2014, 09:57 »

1. Забыл указать, у меня Qt4.8, там нет QAtomicInt::load(). Насколько это критично?
2. Не совсем понял, что происходит здесь:
Код:
if (dst.testAndSetOrdered(cur, val)) 
return !cnt->mActiveReaders;  // enable write if there are no active readers

Код:
	if (!BeginWrite(data->mCount))
writeSemaphore.acquire();

// write data content
theMem.lock();

Если нет активных читателей мы пропускаем захват семафора, но сразу делаем lock?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #14 : Ноябрь 06, 2014, 11:01 »

1. Забыл указать, у меня Qt4.8, там нет QAtomicInt::load(). Насколько это критично?
Тогда замените на просто присваивание, напр cur = dst

2. Не совсем понял, что происходит здесь:
Код:
if (dst.testAndSetOrdered(cur, val)) 
return !cnt->mActiveReaders;  // enable write if there are no active readers

Код:
	if (!BeginWrite(data->mCount))
writeSemaphore.acquire();

// write data content
theMem.lock();

Если нет активных читателей мы пропускаем захват семафора, но сразу делаем lock?
В любом случае мы увеличиваем число писателей. Если на этот момент не было активных читателей - писатель сразу идет писать, иначе ждет на семафоре пока последний отчитавшийся его не откроет. В общем случае неск писателей могут прорваться на запись, поэтому по записи надо делать lock/unlock (а вот по чтению нет).
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.082 секунд. Запросов: 22.