Answer the question
In order to leave comments, you need to log in
Why does WinAPI do a synchronous write?
Encryptor program (but relevant for any file handler). Before the cycle, the following is performed: the beginning of reading a new portion; creation of independent data (for a new portion); waiting for the end of reading (new portion). In the cycle, the following is performed: the beginning of reading a new portion; processing of the current portion (using independent data for the current portion); then start recording the current processed portion; creation of independent data (for a new portion); waiting for the end of reading (new portion) and the end of writing (current portion). After the loop: processing the current chunk (using independent data for the current chunk); then start recording the current processed portion; waiting for the end of the recording (the current portion).
I organize asynchronous access to the file using WinAPI with the following class:
#include <exception>
#include <windows.h>
#include <cstdint>
class AsyncBinFile
{
public:
class Err : public std::exception {};
class ErrOpen : public Err {
public: const char* what() const noexcept override {
return "cannot open file";
} };
class ErrWriteRead : public Err {
public: const char* what() const noexcept override {
return "file write / read error";
} };
AsyncBinFile() = delete;
enum mode_t {WriteNew, Write, Read};
enum buf_mode_t {NoBuffering = true, Buffering = false};
AsyncBinFile (const char* name, mode_t mode, buf_mode_t buf_mode = Buffering);
void close();
~AsyncBinFile() {close();}
AsyncBinFile(const AsyncBinFile&) = delete;
AsyncBinFile& operator=(const AsyncBinFile&) = delete;
HANDLE file_handler() const noexcept {return fh;}
void begin_write (const uint8_t* a, uint32_t n);
void begin_read (uint8_t* a, uint32_t n);
void wait();
void seek (uint64_t offset)
{ovl.OffsetHigh = DWORD(offset>>(sizeof(DWORD)*8)); ovl.Offset = DWORD(offset);}
uint64_t tell()
{return (uint64_t(ovl.OffsetHigh)<<(sizeof(DWORD)*8)) | ovl.Offset;}
uint64_t length();
private:
OVERLAPPED ovl;
HANDLE fh;
DWORD _n;
};
AsyncBinFile::AsyncBinFile (const char* name, mode_t mode, buf_mode_t buf_mode)
{
ovl.Internal = 0; ovl.InternalHigh = 0;
fh = CreateFile (
name,
(mode == WriteNew || mode == Write) ? GENERIC_WRITE : GENERIC_READ,
/*0*/ FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
(mode == WriteNew) ? CREATE_NEW
: ((mode == Read) ? OPEN_EXISTING : OPEN_ALWAYS),
/*FILE_ATTRIBUTE_NORMAL*/0 | FILE_FLAG_OVERLAPPED
| (buf_mode ? (FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH) : 0),
0
);
if (fh == INVALID_HANDLE_VALUE) throw ErrOpen();
ovl.hEvent = CreateEvent (0, /*TRUE*/FALSE, FALSE, 0);
ovl.OffsetHigh = 0; ovl.Offset = 0; _n = 0;
if (ovl.hEvent == INVALID_HANDLE_VALUE) throw ErrOpen();
}
void AsyncBinFile::close()
{
if (fh != INVALID_HANDLE_VALUE) {
CancelIo (fh);
if (ovl.hEvent != INVALID_HANDLE_VALUE) CloseHandle (ovl.hEvent);
CloseHandle (fh);
fh = INVALID_HANDLE_VALUE;
if (_n != 0) throw ErrWriteRead();
}
}
void AsyncBinFile::begin_write (const uint8_t* a, uint32_t n)
{
if (_n != 0) throw ErrWriteRead();
_n = n;
BOOL r = WriteFile (fh, a, n, /*&act_n*/nullptr, &ovl);
if (!r && GetLastError() != ERROR_IO_PENDING) throw ErrWriteRead();
std::cout << "O="<<r<<'\n';
}
void AsyncBinFile::begin_read (uint8_t* a, uint32_t n)
{
if (_n != 0) throw ErrWriteRead();
_n = n;
BOOL r = ReadFile (fh, a, n, /*&act_n*/nullptr, &ovl);
if (!r && GetLastError() != ERROR_IO_PENDING) throw ErrWriteRead();
std::cout << "I="<<r<<'\n';
}
void AsyncBinFile::wait()
{
//while (!HasOverlappedIoCompleted(&ovl));
DWORD act_n;
BOOL r = GetOverlappedResult (fh, &ovl, &act_n, TRUE);
if (r == 0 || act_n != _n) throw ErrWriteRead();
seek (tell() + _n); _n = 0;
}
uint64_t AsyncBinFile::length()
{
DWORD high;
DWORD low = GetFileSize (fh, &high);
return (uint64_t(high)<<(sizeof(DWORD)*8)) | low;
}
static uint64_t buf_a [(BUF_LEN+7)/8];
static uint64_t buf_b [(BUF_LEN+7)/8];
static uint64_t buf_g [(BUF_LEN+7)/8];
{ /*...*/
AsyncBinFile fin (_f_i, AsyncBinFile::Read);
AsyncBinFile fout (_f_o, AsyncBinFile::WriteNew);
uint64_t bytes_to_proc, file_len;
uint32_t portion, portion_next;
uint64_t *buf, *buf_next;
file_len = fin.length();
bytes_to_proc = file_len;
buf = buf_b; buf_next = buf_a;
init = Encrypt64 (init, key);
portion_next = (bytes_to_proc > BUF_LEN) ? BUF_LEN : bytes_to_proc;
auto x = chrono::steady_clock::now();
fin.begin_read ((uint8_t*)(buf_next), portion_next);
cout << 'i' << chrono::duration<double>(chrono::steady_clock::now()-x).count() << '\n';
//init = MakeGamma (buf_g, portion_next, init, key);
x = chrono::steady_clock::now();
fin.wait();
cout << 'w' << chrono::duration<double>(chrono::steady_clock::now()-x).count() << '\n';
portion = portion_next;
bytes_to_proc -= portion;
portion_next = (bytes_to_proc > BUF_LEN) ? BUF_LEN : bytes_to_proc;
while (portion_next > 0)
{
swap (buf, buf_next);
x = chrono::steady_clock::now();
fin.begin_read ((uint8_t*)(buf_next), portion_next);
cout << 'i' << chrono::duration<double>(chrono::steady_clock::now()-x).count() << '\n';
//XOR (buf, buf_g, portion);
x = chrono::steady_clock::now(); //
fin.wait(); // перенос из низа
cout << 'w' << chrono::duration<double>(chrono::steady_clock::now()-x).count() << '\n'; //
x = chrono::steady_clock::now();
fout.begin_write ((uint8_t*)(buf), portion);
cout << 'o' << chrono::duration<double>(chrono::steady_clock::now()-x).count() << '\n';
//init = MakeGamma (buf_g, portion_next, init, key);
//x = chrono::steady_clock::now();
// fin.wait(); перенос вверх
//cout << 'w' << chrono::duration<double>(chrono::steady_clock::now()-x).count() << '\n';
x = chrono::steady_clock::now();
fout.wait();
cout << 'w' << chrono::duration<double>(chrono::steady_clock::now()-x).count() << '\n';
//PB.show (file_len-bytes_to_proc, file_len);
portion = portion_next;
bytes_to_proc -= portion;
portion_next = (bytes_to_proc > BUF_LEN) ? BUF_LEN : bytes_to_proc;
}
XOR (buf_next, buf_g, portion);
fout.begin_write ((uint8_t*)(buf_next), portion);
fout.wait();
/*...*/ }
I=0
i0.234375
w1.26562
I=0
i0.03125
w1.48438
O=0
o0
w0.125
I=1
i0
w0
O=0
o0.0625
w0
. . .
Answer the question
In order to leave comments, you need to log in
In a manual it is directly written that the asynchronous operation can be executed and synchronously - here as venda decides.
By the way, why did Boost::asio not please you?
Perhaps this is the case https://docs.microsoft.com/en-RU/troubleshoot/wind...
File extension
Another reason for synchronous completion of I/O operations is the operations themselves. On Windows, any write operation to a file that extends its length will be synchronous.
Note
Applications can make the previously mentioned write operation asynchronous by using a function to change the valid file data length and then issuing SetFileValidData WriteFile .
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question