На жестком диске есть несколько больших двоичных файлов (обычно по 16–32 МБ каждый), которые должны произвольно считываться и записываться несколькими потоками (конечно, внутри одного и того же процесса).
Я следовал традиционному способу: дескриптор файла из используемых файлов, затем создавал отображенные в память файлы из этих физических файлов, используя CreateFileMapping()
, соответственно создавая представления в 1 МБ, используя MapViewOfFile()
, чтобы произвольно читать и записывать эти блоки памяти (вид).
Суть в том, что эти представления по 1 МБ каждый четко разделены на меньшие зоны между потоками, поэтому гарантируется, что два разных потока никогда не перезаписывают одну и ту же часть. Но - ради оптимизации - я также реализовал «ручной» механизм кэширования, то есть менее используемые представления всегда дают место для часто используемых или недавно использованных для сохранения оперативной памяти.
Производительность и низкое потребление памяти являются обязательными, имеют до сотен тысяч (если не миллионов) выборок в секунду. То есть использование обычных средств синхронизации Windows (мьютексов, критических секций и т. Д.) В любых, но действительно важных местах исключено.
Теоретически я не должен слишком беспокоиться о безопасности потоков, поскольку сами зоны памяти четко разделены. Но у меня все еще могут быть проблемы, когда механизм кэширования сопоставляет / отображает определенные блоки, создаются и отображаются новые файлы и т. Д. Поэтому мне нужно сделать выбор между двумя подходами, как реализовать это:
- Каждый поток использует полностью разделенные дескрипторы файлов и карт, даже те же файлы будут просматриваться через разные файловые дескрипторы каждым из этих потоков.
- Потоки используют один и тот же (общий) дескриптор для определенного файла (здесь может потребоваться некоторая синхронизация), но каждый поток использует свою собственную MMF, созданную из этого общего дескриптора.
- Протекторы совместно используют даже MMF (дополнительная синхронизация здесь!), Но каждый поток использует свои собственные представления, даже если эти представления физически указывают на одну и ту же зону ОЗУ.
- Потоки совместно используют даже представления, поэтому потоки уже нуждаются в синхронизации, когда механизм кэширования отображает новые представления и отображает те, которые используются реже.
Ну, подход 1
будет проще всего реализовать (абсолютно не нужно никакой синхронизации), но это также может быть основным недостатком: не уверен, но у меня такое ощущение, что это просто бросок мертвого кота через забор - как в этом случае Windows будет выполнять все трудоемкие синхронизации, от которых я только что избавился.
Напротив, 4
нужен действительно сложный код и интенсивное использование критических разделов и т. Д., Поэтому я бы исключил его в начале.
Итак, по вашему мнению, какой из этих четырех подходов является оптимальным для обеспечения абсолютно поточно-безопасной работы, но в то же время оптимальная производительность и минимальные объемы ОЗУ (например, должны отображаться те же части файла) физически в одну зону ОЗУ, независимо от разных потоков и дескрипторов). Очевидно, что любые лучшие предложения также приветствуются.