Мне нужно изменить размер очень большого файла mmap без копирования, но при этом разрешить одновременный доступ к потокам читателей.
Простой способ состоит в том, чтобы использовать два сопоставления MAP_SHARED (увеличить файл, затем создать второе сопоставление, включающее в себя регион с расширением) в одном и том же процессе над одним и тем же файлом, а затем разархивировать старое сопоставление, как только все читатели, которые могут получить к нему доступ, законченный. Однако мне любопытно, сработает ли приведенная ниже схема, и если да, то есть ли в этом какое-то преимущество.
- mmap файл с MAP_PRIVATE
- делать доступ только для чтения к этой памяти в нескольких потоках
- либо получить мьютекс для файла, записать в память (предположим, это сделано таким образом, что читатели, которые могут читать эту память, не испортили его)
- или получите мьютекс, но увеличьте размер файла и используйте mremap, чтобы переместить его на новый адрес (измените размер отображения без копирования или ненужного ввода-вывода файла).
Сумасшедшая часть входит в (4). Если вы перемещаете память, старые адреса становятся недействительными, и читатели, которые все еще читают ее, могут внезапно иметь нарушение прав доступа. Что если мы изменим считыватели, чтобы перехватить это нарушение прав доступа, а затем перезапустить операцию (т.е. не перечитывать неверный адрес, пересчитать адрес с учетом смещения и новый базовый адрес из mremap.) Да, я знаю, что это зло , но, на мой взгляд, читатели могут только успешно прочитать данные по старому адресу или потерпеть неудачу с нарушением прав доступа и повторить попытку. Если будут приняты достаточные меры предосторожности, то должен быть безопасным. Поскольку изменение размера происходит не часто, читатели в конечном итоге преуспеют и не будут зацикливаться на повторных циклах.
Проблема может возникнуть, если это старое адресное пространство будет использоваться повторно, пока читатель все еще имеет указатель на него. Тогда не будет никакого нарушения прав доступа, но данные будут неверными, и программа попадет в единорог и заполненную конфетами землю неопределенного поведения (где обычно нет ни единорогов, ни конфет.)
Но если вы полностью контролировали распределение и могли убедиться, что любые распределения, которые происходят в течение этого периода, никогда не будут повторно использовать это старое адресное пространство, тогда это не должно быть проблемой, и поведение не должно быть неопределенным.
Я прав? Может ли это работать? Есть ли в этом преимущество перед использованием двух сопоставлений MAP_SHARED?