@@ -18,7 +18,6 @@ bool CScanFile::Open(const wchar_t* const filename, const bool asyncMode)
1818 {
1919 return false ;
2020 }
21-
2221 assert (this ->_hEvent == nullptr );
2322
2423 const DWORD dwDesiredAccess = FILE_READ_DATA | FILE_READ_ATTRIBUTES; // minimal required rights
@@ -38,6 +37,7 @@ bool CScanFile::Open(const wchar_t* const filename, const bool asyncMode)
3837 return false ;
3938 }
4039
40+ // Init data for async IO:
4141 this ->_hEvent = CreateEventW (nullptr , TRUE , FALSE , nullptr );
4242
4343 if (this ->_hEvent == nullptr )
@@ -56,6 +56,8 @@ bool CScanFile::Open(const wchar_t* const filename, const bool asyncMode)
5656
5757void CScanFile::Close ()
5858{
59+ this ->LockFreecClean ();
60+
5961 if (this ->_pViewOfFile != nullptr )
6062 {
6163 UnmapViewOfFile (this ->_pViewOfFile );
@@ -129,6 +131,8 @@ std::optional<std::string_view> CScanFile::MapToMemory()
129131 return std::string_view (static_cast <const char *>(this ->_pViewOfFile ), fileSizeAsSizeT);
130132}
131133
134+ // ////////////////////////////////////////////////////////////////////////
135+
132136__declspec (noinline) // noinline is added to help CPU profiling in release version
133137bool CScanFile::Read(char * const buffer, const size_t bufferLength, size_t & readBytes)
134138{
@@ -152,6 +156,8 @@ bool CScanFile::Read(char* const buffer, const size_t bufferLength, size_t& read
152156 return !!succeeded;
153157}
154158
159+ // ////////////////////////////////////////////////////////////////////////
160+
155161__declspec (noinline) // noinline is added to help CPU profiling in release version
156162bool CScanFile::AsyncReadStart(char * const buffer, const size_t bufferLength)
157163{
@@ -210,3 +216,132 @@ bool CScanFile::AsyncReadWait(size_t& readBytes)
210216
211217 return true ;
212218}
219+
220+ // ////////////////////////////////////////////////////////////////////////
221+
222+ bool CScanFile::LockFreecInit ()
223+ {
224+ if (this ->_pThread != nullptr )
225+ {
226+ return false ;
227+ }
228+
229+ this ->_threadFinishSignal = false ;
230+ this ->_threadOperationReadStartSignal = false ;
231+ this ->_threadOperationReadCompletedSignal = false ;
232+ {
233+ std::lock_guard<std::mutex> lock (this ->_protectThreadData );
234+ this ->_pThreadReadBuffer = nullptr ;
235+ this ->_threadReadBufferSize = 0 ;
236+ this ->_threadActuallyReadBytes = 0 ;
237+ this ->_threadReadSucceeded = false ;
238+ }
239+
240+ this ->_pThread = std::make_unique<std::thread>(&CScanFile::LockFreeThread, this );
241+
242+ return true ;
243+ }
244+
245+ void CScanFile::LockFreecClean ()
246+ {
247+ if (this ->_pThread != nullptr )
248+ {
249+ this ->_threadFinishSignal = true ;
250+ this ->_pThread ->join ();
251+ this ->_pThread .reset ();
252+ }
253+ }
254+
255+ __declspec (noinline) // noinline is added to help CPU profiling in release version
256+ bool CScanFile::LockFreeReadStart(char * const buffer, const size_t bufferLength)
257+ {
258+ if (this ->_pThread == nullptr || this ->_threadOperationInProgress )
259+ {
260+ return false ;
261+ }
262+
263+ this ->_threadOperationInProgress = true ;
264+
265+ this ->_threadOperationReadCompletedSignal = false ;
266+
267+ {
268+ std::lock_guard<std::mutex> lock (this ->_protectThreadData );
269+ this ->_pThreadReadBuffer = buffer;
270+ this ->_threadReadBufferSize = bufferLength;
271+ this ->_threadActuallyReadBytes = 0 ;
272+ this ->_threadReadSucceeded = false ;
273+ }
274+
275+ this ->_threadOperationReadStartSignal = true ;
276+
277+ return true ;
278+ }
279+
280+ __declspec (noinline) // noinline is added to help CPU profiling in release version
281+ bool CScanFile::LockFreeReadWait(size_t & readBytes)
282+ {
283+ if (this ->_pThread == nullptr || !this ->_threadOperationInProgress )
284+ {
285+ return false ;
286+ }
287+
288+ this ->_threadOperationInProgress = false ;
289+
290+ while (!this ->_threadOperationReadCompletedSignal )
291+ {
292+ // nothing
293+ }
294+
295+ {
296+ std::lock_guard<std::mutex> lock (this ->_protectThreadData );
297+ readBytes = this ->_threadActuallyReadBytes ;
298+ if (!this ->_threadReadSucceeded )
299+ {
300+ return false ;
301+ }
302+ }
303+
304+ return true ;
305+ }
306+
307+ void CScanFile::LockFreeThread ()
308+ {
309+ while (true )
310+ {
311+ if (this ->_threadFinishSignal )
312+ {
313+ // thread exit signal is caught
314+ break ;
315+ }
316+
317+ if (!this ->_threadOperationReadStartSignal )
318+ {
319+ // nothing to do
320+ continue ;
321+ }
322+
323+ this ->_threadOperationReadStartSignal = false ;
324+
325+ char * buffer = nullptr ;
326+ size_t bufferSize = 0 ;
327+
328+ {
329+ std::lock_guard<std::mutex> lock (this ->_protectThreadData );
330+ buffer = this ->_pThreadReadBuffer ;
331+ bufferSize = this ->_threadReadBufferSize ;
332+ }
333+
334+ size_t readBytes = 0 ;
335+ const bool readOk = this ->Read (buffer, bufferSize, readBytes);
336+
337+ {
338+ std::lock_guard<std::mutex> lock (this ->_protectThreadData );
339+ this ->_threadActuallyReadBytes = readBytes;
340+ this ->_threadReadSucceeded = readOk;
341+ }
342+
343+ this ->_threadOperationReadCompletedSignal = true ;
344+ }
345+ }
346+
347+ // ////////////////////////////////////////////////////////////////////////
0 commit comments