Имеется вопрос, есть в проекте (операционка QNX4.25) несколько разделяемых объектов памяти, для взаимодействия между процессами. Есть один писатель в каждую из них и несколько читателей, я написал несколько функций оберток вида:
Так вот, как видно в функции XXXX_ShmemCopy, копирование данных в область и из нее, производится вызовом memcpy, обернутым в семафор и дополнительным отключением прерываний на момент копирования, чтобы обеспечить атомарность операции. Есть ли вообще смысл в такой перестраховке на однопроцессорной системе? Минус в использовании _disable()/_enable() при больших объемах копирования (которых скорее всего не будет), на момент выполнения операции, стопорится работа всей системы, или если вызовов XXXX_ShmemCopy будет много (а их скорее всего будет много), то рискуем то и делать что бесконечно выключать/включать прерывания. Так же есть ли необходимость оборачивания простых операций вида "Область->переменная = что-то записать", понятное дело не делая справа от "=" сложных операций, будет ли такая операция выполнена атомарно?
wait/post является атомарным объектом для синхронизации к шаред мемори
значит sti/cli не нужно
да операционка может прервать ваше копирование
но какое это отношение имеет в разделяемой памяти ?
I>Так вот, как видно в функции XXXX_ShmemCopy, копирование данных в область и из нее, производится вызовом memcpy, обернутым в семафор и дополнительным отключением прерываний на момент копирования, чтобы обеспечить атомарность операции. Есть ли вообще смысл в такой перестраховке на однопроцессорной системе?
На однопроцессорной машине достаточно одного запрета прерываний.
I> Минус в использовании _disable()/_enable() при больших объемах копирования (которых скорее всего не будет), на момент выполнения операции, стопорится работа всей системы, или если вызовов XXXX_ShmemCopy будет много (а их скорее всего будет много), то рискуем то и делать что бесконечно выключать/включать прерывания.
Обработчик прерывания может обратиться к той же памяти в середине операции, кроме того по выходу из обработчика планировщик может переключить контекст на другой процесс, поэтому к спинлокам добавляют запрет прерываний.
Семафоров же одних достаточно.
I> Так же есть ли необходимость оборачивания простых операций вида "Область->переменная = что-то записать", понятное дело не делая справа от "=" сложных операций, будет ли такая операция выполнена атомарно?
Нужно использовать atomic_* функции или atomic_t тип. Выражение справа роли не играет.
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
I>Так же есть ли необходимость оборачивания простых операций вида "Область->переменная = что-то записать", понятное дело не делая справа от "=" сложных операций, будет ли такая операция выполнена атомарно?
А что, если shared-memory buffer представить в виде кольцевого буфера, разбитого на блоки вида, например:
struct block
{
int flags;
char buffer[...]
};
Сначала у всех блоков flags = ready to write. Когда писателю нужно записать что-то, он ищет первый свободный для себя блок (flags = ready to write), копирует в буфер данные и выставляет flags = ready to read. Читатели в свою очередь пробегаются по кольцевому буферу, ждут flags = ready to read и, когда данные есть, читают их и по окончанию выставляют блоку снова flags = ready to write. Не?
Здравствуйте, -prus-, Вы писали:
P>Сначала у всех блоков flags = ready to write. Когда писателю нужно записать что-то, он ищет первый свободный для себя блок (flags = ready to write), копирует в буфер данные и выставляет flags = ready to read. Читатели в свою очередь пробегаются по кольцевому буферу, ждут flags = ready to read и, когда данные есть, читают их и по окончанию выставляют блоку снова flags = ready to write. Не?
Это очень медленно, потому что префетчер в ЦПУ не справится с предсказанием какие именно данные из ОЗУ подгружать в кэш ЦПУ.
Лучше, когда есть отдельный массив для флагов, целиком помещающийся в одну или несколько кэш-линий.
Тогда: Проверка флагов для поиска свободного блока будет происходить максимально быстро
Данные записываемые в ОЗУ на самом деле будут оседать в кэше ЦПУ выталкиваясь в буффер записи ОЗУ.
Ошибки префетчера будут аффектить производительность лишь чтение данных из ОЗУ, если она производилось очень давно или же делал её ЦПУ на другом сокете.
Здравствуйте, lpd, Вы писали:
lpd>>На однопроцессорной машине достаточно одного запрета прерываний.
Да, но судя по всему плохая идея использовать их в ОСРВ.
lpd>>Семафоров же одних достаточно.
Именно в таком виде сейчас и оставил.
lpd>>Нужно использовать atomic_* функции или atomic_t тип. Выражение справа роли не играет.
Таких в QNX 4.25 не имеется.