Найкраще рішення - реалізувати запис асинхронізації з подвійним буферизацією.
Подивіться на часовий рядок:
------------------------------------------------>
FF|WWWWWWWW|FF|WWWWWWWW|FF|WWWWWWWW|FF|WWWWWWWW|
'F' означає час заповнення буфера, а 'W' - час запису буфера на диск. Отже, проблема у витрачанні часу між написанням буферів на файл. Однак, застосувавши запис на окремому потоці, ви можете почати заповнювати наступний буфер одразу так:
------------------------------------------------> (main thread, fills buffers)
FF|ff______|FF______|ff______|________|
------------------------------------------------> (writer thread)
|WWWWWWWW|wwwwwwww|WWWWWWWW|wwwwwwww|
F - заповнення 1-го буфера
f - заповнення 2-го буфера
W - запис 1-го буфера до файлу
w - написання 2-го буфера до файлу
_ - зачекайте, поки операція завершена
Такий підхід із заміною буфера дуже корисний, коли заповнення буфера вимагає більш складних обчислень (отже, більше часу). Я завжди реалізую клас CSequencesStreamWriter, який приховує всередині асинхронну запис, тому для кінцевого користувача інтерфейс має просто функції запису.
А розмір буфера повинен бути кратним розміру кластера диска. В іншому випадку ви отримаєте низьку продуктивність, записавши один буфер на 2 сусідні кластери диска.
Запис останнього буфера.
Під час останнього виклику функції Write, ви повинні переконатися, що поточний буфер заповнений також слід записати на диск. Таким чином, CSequencesStreamWriter повинен мати окремий метод, скажімо, Finalize (остаточний змив буфера), який повинен записати на диск останню частину даних.
Помилка обробки.
Хоча код починає заповнювати другий буфер, а 1-й записується в окремий потік, але запис чомусь не вдається, головний потік повинен знати про цей збій.
------------------------------------------------> (main thread, fills buffers)
FF|fX|
------------------------------------------------> (writer thread)
__|X|
Припустимо, що в інтерфейсі CSequentialStreamWriter функція Write має функцію Write, яка повертає bool або викидає виняток, таким чином, маючи помилку в окремому потоці, ви повинні пам'ятати про цей стан, тому наступного разу, коли ви зателефонуєте Write або Finilize на основний потік, метод повернеться Неправдивий або викине виняток. І зовсім неважливо, в який момент ви перестали заповнювати буфер, навіть якщо ви записали деякі дані попереду після відмови - швидше за все, файл буде пошкоджений і марний.