locked
About writing text into file

    Question

  • I'm  working on a app for which am writing the code for logging some debug information into a local file. But I encounter some problems while doing this.

    I found that if the log function was called frequently( but absolutely didn't make the file IO overload) some text will be lost and some of them were in a mess order. 

    Here is my code in log() function:

    LogEntity::Log(wchar_t* logContent)

    {

        String^ logString = ref new String(logContent);

        EnterCriticalSection(&mCriticalSection) // mCriticalSection is in type of CRITICAL_SECTION and was initialised.

       auto op = FielIO::AppendTextAsync(mLogFile, logString);

       op->Completed = ref new AsyncActioonCompletedHandler([this](IAsyncAction^ op, AsyncStatus){

             LeaveCriticalSection(&mCriticalSection);

       }

    }// end

    I used a "for(xxx)" loop to call this function to do some test, I found some of the text were lost and some of them were in a mess order(the order am saying is the time sequence ).

    If a use Event object, that is call CreateEventEx() to create a event object.When the append operation is completed, call SetEvent() to release the control. This made the log messages in the right time sequence, but every single log function call will take 5ms ...  By the way, if I just directly return after  got the event control , the time spent on the single function call was almost the same.

    The log function is supposed to be called from different threads and sometimes it will be called  fairly  frequently. So if you have any idea about my case, please give me some suggesting. Thanks.

    Thursday, July 25, 2013 12:38 PM

Answers

  • The critical section will block other threads from logging until AppendTextAsync completes, but they will allow more calls from the current thread. The ordering issue sounds like multiple calls from the current thread going through while other threads are blocked by the critsec. SetEvent is closer to what you want, and you can change the logging so it doesn't block as long.

    Instead of blocking while the log is being written out queue up the log entries and write them from a single thread. This will require much less locking and be more parallel.

    If you are saving the log file into the app data directory then you have write access and can save out directly with the Win32 api rather than asynchronously via the file broker. This will be faster as well

    --Rob

    Thursday, July 25, 2013 2:03 PM
    Owner
  • Hi

    You can tray by following instead of using event for sync.

    HRESULT  taskResult = S_OK;
    
    	create_task(FileIO::AppendTextAsync( currentFile, ConvertToPlatformString( stringToAppend ), UnicodeEncoding::Utf8 )).then([&](task<void> writeTask)
                {
                    try
                    {
                        writeTask.get();
    					//OutputDebugStringW( stringToAppend.data() );
                        //OutputDebugStringW(  L" Appended successfully \n");
                    }
                    catch(COMException^ ex)
                    {
    					taskResult = ex->HResult;
                        //OutputDebugStringW(L"Failed to append \n");
                    }
                }).get();
    
    		if (S_OK == taskResult)
    		{
    			//Success
    		}
    		else
    		{
    			//Fail
    		}

    OR

    create_task(FileIO::AppendTextAsync( currentFile, ConvertToPlatformString( stringToAppend ), UnicodeEncoding::Utf8 )).then([this, stringToAppend](task<void> writeTask)
                {
                    try
                    {
                        writeTask.get();
    					//OutputDebugStringW( stringToAppend.data() );
                        //OutputDebugStringW(  L" Appended successfully \n");
                    }
                    catch(COMException^ ex)
                    {
                        //OutputDebugStringW(L"Failed to append \n");
                    }
                }).wait();

    Though using new asynchronous APIs is recommended, you can use the standard C fopen/fread/fwrite/etc functions to handle files synchronously. As far I know fopen/fprintf won't create any problem regarding certification issue. Use buffering technique for flushing.


    Friday, July 26, 2013 5:32 AM

All replies

  • The critical section will block other threads from logging until AppendTextAsync completes, but they will allow more calls from the current thread. The ordering issue sounds like multiple calls from the current thread going through while other threads are blocked by the critsec. SetEvent is closer to what you want, and you can change the logging so it doesn't block as long.

    Instead of blocking while the log is being written out queue up the log entries and write them from a single thread. This will require much less locking and be more parallel.

    If you are saving the log file into the app data directory then you have write access and can save out directly with the Win32 api rather than asynchronously via the file broker. This will be faster as well

    --Rob

    Thursday, July 25, 2013 2:03 PM
    Owner
  • Since you are using asynchronous APIs, you may make them block in order to maintain sequence or use buffering technique in order to reduce number of I/O operations. Nota Bene, always try to use separate worker thread instead of UI thread.

    Thursday, July 25, 2013 3:10 PM
  • Since you are using asynchronous APIs, you may make them block in order to maintain sequence or use buffering technique in order to reduce number of I/O operations. Nota Bene, always try to use separate worker thread instead of UI thread.

    Thanks, I added  a buffer to cache the log text and found no performance improvement by doing so. I did a test, that was dropping the log text and then just return with SetEvent(), so no time will be spent on writing file.  Every single call(Log()) will takes 5ms, so the limitation is the Event object.
    Friday, July 26, 2013 1:25 AM
  • Hi

    You can tray by following instead of using event for sync.

    HRESULT  taskResult = S_OK;
    
    	create_task(FileIO::AppendTextAsync( currentFile, ConvertToPlatformString( stringToAppend ), UnicodeEncoding::Utf8 )).then([&](task<void> writeTask)
                {
                    try
                    {
                        writeTask.get();
    					//OutputDebugStringW( stringToAppend.data() );
                        //OutputDebugStringW(  L" Appended successfully \n");
                    }
                    catch(COMException^ ex)
                    {
    					taskResult = ex->HResult;
                        //OutputDebugStringW(L"Failed to append \n");
                    }
                }).get();
    
    		if (S_OK == taskResult)
    		{
    			//Success
    		}
    		else
    		{
    			//Fail
    		}

    OR

    create_task(FileIO::AppendTextAsync( currentFile, ConvertToPlatformString( stringToAppend ), UnicodeEncoding::Utf8 )).then([this, stringToAppend](task<void> writeTask)
                {
                    try
                    {
                        writeTask.get();
    					//OutputDebugStringW( stringToAppend.data() );
                        //OutputDebugStringW(  L" Appended successfully \n");
                    }
                    catch(COMException^ ex)
                    {
                        //OutputDebugStringW(L"Failed to append \n");
                    }
                }).wait();

    Though using new asynchronous APIs is recommended, you can use the standard C fopen/fread/fwrite/etc functions to handle files synchronously. As far I know fopen/fprintf won't create any problem regarding certification issue. Use buffering technique for flushing.


    Friday, July 26, 2013 5:32 AM
  • Mokarrom Hossain

    Thank you for your information!  I will try both of the asynchronous API and Standard C functions. 

    Best Regards.

    Dong

    Monday, July 29, 2013 2:40 AM