Кроссплатформенные и межпроцессные записи atomic int в файл - PullRequest
2 голосов
/ 17 мая 2010

Я пишу приложение, которое должно быть в состоянии обрабатывать много одновременных обращений к нему, как потоками, так и процессами. Так что никакие mutex'ы или блокировки не должны применяться к этому.

Чтобы свести к минимуму использование блокировок, я планирую, чтобы файл был «только для добавления», поэтому все данные сначала добавляются на диск, а затем адрес, указывающий на информацию, которую он обновил. , изменен для ссылки на новый. Поэтому мне нужно будет внедрить небольшую систему блокировок только для того, чтобы изменить этот int так, чтобы он ссылался на новый адрес. Как лучше всего это сделать?

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

  • читатель читает флаг, и он не установлен
  • в это же время писатель записывает флаг и изменяет значение int
  • читатель может прочитать несоответствующее значение!

Я ищу методы блокировки, но все, что я нахожу, это либо методы блокировки потоков, либо блокирование всего файла, а не полей. Разве это невозможно сделать? Как базы данных только для добавления справляются с этим?

редактирование: Я смотрел на то, как это делают базы данных только для добавления (couchDB), и кажется, что они используют поток только для сериализации записей в файл. Означает ли это, что невозможно сделать их встраиваемыми, например, sqlite, без блокировки всего файла блокировками файловой системы?

Спасибо! Cauê

Ответы [ 2 ]

1 голос
/ 17 мая 2010

Будьте осторожны с семантикой добавления вашей файловой системы - она, вероятно, не обеспечивает атомарных операций добавления.

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

Правильный (хотя я не уверен, что это быстро) способ выполнить то, что вам нужно, с помощью rename - это атомарная файловая операция на большинстве файловых систем. Храните самые последние данные в официальном месте файла. Чтобы обновить данные, запишите новые данные во временный файл, а затем переименуйте этот временный файл в официальное местоположение.

1 голос
/ 17 мая 2010

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

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

...