Являются ли файлы с отображением памяти потокобезопасными

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

Однако, немного погуглив, я все еще не уверен. В этой ссылке от Microsoft говорится:

Во-первых, очевидна экономия ресурсов, поскольку оба процесса совместно используют как физическую страницу памяти, так и страницу хранилища жесткого диска, используемую для резервного копирования файла, отображаемого в память. Во-вторых, существует только один набор данных, поэтому все представления всегда согласованы друг с другом. Это означает, что изменения, внесенные на страницу в файле с отображением в память через представление одного процесса, автоматически отражаются в общем представлении файла с отображением в память в другом процессе. По сути, Windows NT не требует специального учета для обеспечения целостности данных для обоих приложений.

Но применимо ли это к потокам, принадлежащим одному и тому же процессу? Это было бы правдоподобно (поскольку мои записи не пересекаются), но я недостаточно знаю о базовой реализации сопоставления памяти (например, что делает бухгалтерия ОС), чтобы быть уверенным.

Пример использования, где myFunction выполняется каждым потоком:

// crt     - index of current thread, in 0..n-1
// n       - thread count
// memArea - pointer to memory location obtained from mapping a file

void myFunction(int crt, int n, int*memArea){
    for (int i=1; i<512; i++)
        memArea[ ( sizeof(int)*( n*i + crt ) ] = n*i+crt;
}

Если бы мне пришлось запустить это, дождаться завершения потоков, отменить сопоставление файла и выйти, получился бы я с файлом, содержащим последовательные целые числа?

Буду признателен за информированный ответ.


person Vlad    schedule 07.11.2011    source источник
comment
Предложение Существует только один набор данных, поэтому все представления всегда согласованы друг с другом, это нормативно. Предложение This означает, что ... имеет толкование. Пояснительные утверждения помогут вам понять нормативный текст; они его не заменяют. Все взгляды на одну машину всегда согласованы друг с другом, независимо от того, находятся ли они в одном процессе или нет. Но если ваши потоки находятся в одном процессе, зачем создавать два представления? Почему бы просто не разделить между ними одну точку зрения?   -  person Raymond Chen    schedule 07.11.2011
comment
Я не против того, чтобы делиться мнением между ветками, честно говоря, думаю, что я бы так и поступил. Но я хотел убедиться, что что-то не упускаю.   -  person Vlad    schedule 07.11.2011
comment
Влад, знаете ли вы, что вы можете писать в разные части файла одновременно из нескольких потоков, используя WriteFile или WriteFileEx с асинхронным дескриптором файла? Для этого вам не нужно использовать отображение памяти (хотя отображение памяти также будет работать).   -  person Harry Johnston    schedule 07.11.2011
comment
@ Гарри, я не знал, но хорошо знать, что это разрешено.   -  person Vlad    schedule 08.11.2011


Ответы (2)


Вам нужно будет добавить синхронизацию независимо от того, осуществляется ли доступ к представлению MMF из нескольких процессов или из нескольких потоков внутри одного процесса. Fwiw, нет никакого смысла использовать MMF для разделения памяти внутри одного процесса. Потоки уже совместно используют адресное пространство.

person Hans Passant    schedule 07.11.2011
comment
Потенциальным вариантом использования MMF здесь, при условии, что он является потокобезопасным, было бы упрощение записи в один файл из многопоточного кода, позволяя ОС иметь дело с фактическим сохранением данных с виртуальной машины на диск, когда это необходимо. - person Vlad; 07.11.2011
comment
Он заботится о записи, а не о безопасности потоковой передачи. MMF будет полезен только в этом случае, когда вы не пишете последовательно, а повторно записываете один и тот же раздел файла. - person Hans Passant; 07.11.2011
comment
Ганс, неужели никакая синхронизация не требуется, поскольку разные потоки обращаются к разным частям адресного пространства? - person Harry Johnston; 07.11.2011
comment
@ Гарри, не имеет смысла иметь только один поток, который пишет. Кто-то должен читать, иначе это пустая трата времени. Чтение необходимо синхронизировать с записью. По крайней мере, это традиционное использование разделяемой памяти. - person Hans Passant; 07.11.2011
comment
@Hans, он использует отображение памяти как способ записи файла. Каждый поток обращается к непересекающемуся сегменту адресного пространства. В этом случае синхронизация не требуется. - person Harry Johnston; 08.11.2011
comment
Я не знаю, является ли отображение файла в памяти более или менее эффективным, чем запись желаемых фрагментов данных в буферы и вызов WriteFile [Ex] из нескольких потоков. - person Harry Johnston; 08.11.2011

Но применимо ли это к потокам, принадлежащим одному и тому же процессу?

да. Если один поток изменяет часть данных в сопоставлении, то все другие потоки немедленно видят это изменение.

Вам необходимо убедиться, что потоки координируют свои изменения, чтобы ни один поток не имел доступа к противоречивому представлению (например, весь доступ осуществляется через критический раздел).

person Richard    schedule 07.11.2011
comment
На самом деле, я хотел бы знать, безопасно ли избавляться от критических секций - в контексте записи в неперекрывающиеся места. - person Vlad; 07.11.2011
comment
@Vlad Я пытаюсь быть универсальным здесь, блокировки - это не единственный способ координировать доступ, чтобы избежать противоречивого представления, разные потоки, обращающиеся к разным частям памяти, также достигли бы этого, не имея совместного доступа (что является наиболее производительным типом совместного использования ). Обратите внимание, что я привожу критические разделы в качестве примера. - person Richard; 07.11.2011