能否同时多次调用WriteAsync?文件写入位置竞态问题探讨
并行调用FileStream.WriteAsync的潜在问题
我想要实现如下操作:
byte[] b1,b2,b3,... task1=fs.WriteAsync(b1, 0, b1.Length); task2=fs.WriteAsync(b2, 0, b2.Length); task3=fs.WriteAsync(b3, 0, b3.Length); ... Task.WaitAll(task1,task2,task3,...)
不过我认为这存在问题,除非fs处于追加模式。这完全取决于WriteAsync是在返回任务之前还是之后更新文件位置。
情况1:WriteAsync在等待系统调用前更新文件指针
如果它在等待系统调用前就更新文件指针,比如旧版WriteAsync的伪代码:
async ValueTask WriteAsyncBefore(ReadOnlyMemory<byte> buffer) { long oldEndOfFile = GetFileLength(_handle); // 第1次系统调用 long newEndOfFile = _position + buffer.Length; if (newEndOfFile > oldEndOfFile) // 对空文件的每次写入都成立 { ExtendTheFile(_handle, newEndOfFile); // 第2次系统调用 SetFilePosition(_handle, newEndOfFile); // 第3次系统调用 _position += buffer.Length; } await WriteFile(_handle, buffer); // 第4次系统调用 }
这种情况下不会有问题,因为每个WriteAsync都能使用前一个已正确累加的位置。
情况2:WriteAsync在WriteFile之后修改文件位置
但更可能的情况是WriteAsync在WriteFile之后修改文件位置,这会导致竞态条件,比如新版WriteAsync:
async ValueTask WriteAsyncAfter(ReadOnlyMemory<byte> buffer) { await WriteFile(_handle, buffer, _position); // 唯一的系统调用 _position += buffer.Length; }
手动设置文件位置也无法解决问题
手动设置文件位置也无济于事:
pos=0; fs.Seek(pos,Begin); task1=fs.WriteAsync(b1, 0, b1.Length); pos+=b1.Length; fs.Seek(pos,Begin); // 如果之前的WriteAsync此时完成并修改了文件位置怎么办? task2=fs.WriteAsync(b2, 0, b2.Length); pos+=b2.Length; fs.Seek(pos,Begin); // 同样的问题 task3=fs.WriteAsync(b3, 0, b3.Length);
内容的提问来源于stack exchange,提问作者elflyao
相关产品推荐
相关产品推荐

