Допустим ли следующий шаблон многопоточных вызовов для .Net FileStream ?
Несколько потоков, вызывающих такой метод:
ulong offset = whatever; // different for each thread
byte[] buffer = new byte[8192];
object state = someState; // unique for each call, hence also for each thread
lock(theFile)
{
theFile.Seek(whatever, SeekOrigin.Begin);
IAsyncResult result = theFile.BeginRead(buffer, 0, 8192, AcceptResults, state);
}
if(result.CompletedSynchronously)
{
// is it required for us to call AcceptResults ourselves in this case?
// or did BeginRead already call it for us, on this thread or another?
}
Где AcceptResults
:
void AcceptResults(IAsyncResult result)
{
lock(theFile)
{
int bytesRead = theFile.EndRead(result);
// if we guarantee that the offset of the original call was at least 8192 bytes from
// the end of the file, and thus all 8192 bytes exist, can the FileStream read still
// actually read fewer bytes than that?
// either:
if(bytesRead != 8192)
{
Panic("Page read borked");
}
// or:
// issue a new call to begin read, moving the offsets into the FileStream and
// the buffer, and decreasing the requested size of the read to whatever remains of the buffer
}
}
Я запутался, потому что документация мне неясна. Например, класс FileStream говорит:
Любые открытые статические члены этого типа являются потокобезопасными. Любые члены экземпляра не гарантированно являются потокобезопасными.
Но документация для BeginRead, похоже, предполагает наличие нескольких запросов на чтение в полете:
Несколько одновременных асинхронных запросов приводят к неопределенности порядка выполнения запроса.
Разрешено ли многократное чтение в полете или нет? Пишет? Является ли этот способ безопасным для определения местоположения потока Position
между вызовом Seek и вызовом BeginRead
? Или эту блокировку нужно удерживать вплоть до EndRead
, следовательно, только одно чтение или запись в полете за раз?
Я понимаю, что обратный вызов будет происходить в другом потоке, и моя обработка state
, buffer
обрабатывает это таким образом, который допускает множественное чтение в полете.
Далее, кто-нибудь знает, где в документации найти ответы на эти вопросы? Или статья написана кем-то в курсе? Я искал и ничего не могу найти.
Соответствующая документация:
FileStream класс
Метод поиска
Метод BeginRead
EndRead
Интерфейс IAsyncResult
Редактировать с новой информацией
Быстрая проверка с помощью Reflector показывает, что BeginRead фиксирует позицию потока в состоянии для каждого вызова (некоторые поля структуры NativeOverlapped). Похоже, что EndRead не проверяет позицию потока, по крайней мере, не совсем очевидным образом. Это не является окончательным, очевидно, потому что это может быть неочевидным способом или может не поддерживаться базовым нативным API.