locked
Fail to write file when there are many file operation tasks at the same time.

    Question

  • Hi MSFT,

    There is a critical issue when to create and write many files at the same time.

    It works well when there is not big task (or delay logich) during DataWriter.

    If there is a big task (add an empty loop to simulate a big task delay), all the writing operation will fail.

    following is the test code:

    for (int i = 0; i < 100; i++)
    	{
    		String^ fileName;
    		MainPage^ page = this;
    		fileName = "sample" + MyToString(i) + ".txt";
    		StorageFolder^ documentsFolder = KnownFolders::DocumentsLibrary;
    		auto fileOperation = documentsFolder->CreateFileAsync(fileName, CreationCollisionOption::ReplaceExisting);
    		fileOperation->Completed = ref new AsyncOperationCompletedHandler<StorageFile^>([page](IAsyncOperation<StorageFile^>^ operation) 
    		{
    			if (operation->Status == AsyncStatus::Completed)
    			{
    				StorageFile^ fileNew = operation->GetResults();
    				page->Scenario1Output_textblock->Text = "The file " + fileNew->FileName + " was created.";
    				StorageFile^ storagefileSample = operation->GetResults();
    				auto openOperation = storagefileSample->OpenAsync(FileAccessMode::ReadWrite);
    				openOperation->Completed = ref new AsyncOperationCompletedHandler<IRandomAccessStream^>([page](IAsyncOperation<IRandomAccessStream^>^ operation)
    				{
    					if (operation->Status == AsyncStatus::Completed)
    					{
    						// Create a DataReader to read the opened file's contents
    						IRandomAccessStream^ accessStream = operation->GetResults();
    						IOutputStream^ outputStream = accessStream->GetOutputStreamAt(0);
    						DataWriter^ dataWriter  = ref new DataWriter(outputStream);
    
    						// Write the string and store it in the writer
    						dataWriter->WriteString(page->Scenario2Textbox->Text);
    						auto writeOperation = dataWriter->StoreAsync();
    						for (int i = 0; i < 1000000000; i++)
    						{
    							//just did a delay to simulate a big task at here (such as read/write a large file)
    						}
    						writeOperation->Completed = ref new AsyncOperationCompletedHandler<unsigned int>([page, outputStream](IAsyncOperation<unsigned int>^ operation)
    						{
    							auto flushOperation = outputStream->FlushAsync();
    							flushOperation->Completed = ref new AsyncOperationCompletedHandler<bool>([page](IAsyncOperation<bool>^ operation)
    							{
    								page->Scenario2Output_textblock->Text = "\"" + page->Scenario2Textbox->Text + "\" was written to sample.txt";
    							});
    							flushOperation->Start();
    						});
    						writeOperation->Start();
    					}
    				});
    				openOperation->Start();
    			}
    			else
    			{
    				page->Scenario1Output_textblock->Text = "There was an error creating sample.txt.";
    			}
    		});
    		fileOperation->Start();
    	}

    Thanks,

    kevin.

    Tuesday, March 6, 2012 9:21 AM

All replies

  • How about parallel_for?

    NEU_ShieldEdge

    Wednesday, March 7, 2012 12:56 PM
  • I would also suggest updating to Consumer Preview and using the Consumer Preview version of the FileAccessSample as the sample code you posted won't compile any longer. The new version of the sample also now uses PPL tasks.


    David Lamb

    Thursday, March 8, 2012 4:10 AM
    Moderator
  • Hi David,

    Thanks a lot for your reply.

    The posted code is Developer Preview sample code.

    I will have a double check on consumer preview.

    Thanks,

    kevin.

    Thursday, March 8, 2012 10:35 AM
  • Hi David,

    I have a double check on Consumer Preview about this issue.

    And it still can be reproduced.

    Test code as following.

    for (int i = 0; i < 100; i++)
     
    {
     
    String^ fileName;
     
    fileName = "sample" + i + ".txt";
     
    task<StorageFile^>(KnownFolders::DocumentsLibrary->CreateFileAsync(fileName, CreationCollisionOption::ReplaceExisting)).then([this](StorageFile^ file)
     
    {
     
    Scenario1Output_textblock->Text = "The file '" + file->Name + "' was created.";
     
    String^ userContent = Scenario2Textbox->Text;
     
    if (userContent != nullptr && !userContent->IsEmpty())
     
    {
     
    for (int j = 0; j < 1000000000; j++)
     
    {
        //just try to delay sometime and simulate a big task;
    }
     
    task<void>(FileIO::WriteTextAsync(file, userContent)).then([this, userContent, file]()
     
    {
     
    Scenario2Output_textblock->Text = "The following text was written to '" + file->Name + "':\n\n" + userContent;
     
    });
     
    }
     
    else
     
    {
     
    Scenario2Output_textblock->Text = "The text box is empty, please write something and then click 'Write' again.";
     
    }
     
    });
     
    
    
    }
    

    It works well if the empty for loop is removed.

    NOTE: I want to have a conferm whether this is exit or known issue or not. But not for asking a workaround method 

    Thanks,

    Kevin.

    Thursday, March 8, 2012 11:26 AM
  • Thanks Kevin,. Looking into this now. There were some bugs in DP along these lines that were fixed over that past 5 months. Problems reported on Consumer Preview are of most interest at this time.

    David Lamb

    Thursday, March 8, 2012 11:15 PM
    Moderator
  • Hi David,

    Thanks so much for your quick reply and detail comments.

    I have work around this issue by serialization.

    Do you have any better solution or suggestion?

    Thanks,

    Kevin.

    Friday, March 9, 2012 1:24 AM
  • Can you post the error or exception you are receiving? I'm not seeing a problem on the first attempt. I'll try lengthening the delay.


    David Lamb

    Friday, March 9, 2012 2:12 AM
    Moderator
  • Hi David,

    Maybe you have a better performance test machine. You could delay more time and try to reproduce it.

    As your requirement, I add exception catch. But couldn't get any exception, application just be hang.

    exception catch code as following: I am not sure it is reasonable.

    for(int i = 0; i < 100; i++)
    {
     
    try
    {
    String^ fileName;
     
    fileName = "sample" + i + ".txt";
     
    task<StorageFile^>(KnownFolders::DocumentsLibrary->CreateFileAsync(fileName, CreationCollisionOption::ReplaceExisting)).then([this](StorageFile^ file)
     
    {
     
    Scenario1Output_textblock->Text = "The file '" + file->Name + "' was created.";
     
    String^ userContent = Scenario2Textbox->Text;
     
    if (userContent != nullptr && !userContent->IsEmpty())
     
    {
     
    for (int j = 0; j < 1000000000; j++)
     
    {
        //just try to delay sometime and simulate a big task;
    }
    try
    { 
    task<void>(FileIO::WriteTextAsync(file, userContent)).then([this, userContent, file]()
     
    {
     
    Scenario2Output_textblock->Text = "The following text was written to '" + file->Name + "':\n\n" + userContent;
     
    });
    }
    catch(Platform::Exception^ e)
    {
    //do something at here and set a break. but cann't reach hear.
    
    } 
    }
     
    else
     
    {
     
    Scenario2Output_textblock->Text = "The text box is empty, please write something and then click 'Write' again.";
     
    }
     
    });
     
    }
    catch(Platform::Exception^ e)
    {
         //do something at here and set a break. but cann't reach hear.
    }
    
    }

    Thanks,

    kevin.

    Friday, March 9, 2012 6:06 AM
  • Hi Kevin,

    I've been unable to repro any problems with a hang implementing a longer delay or running on a slower system. I'm wondering if it's possible what you are perceiving as a hang is due to your UI thread being tied up.

    Wrapping the initial creation of the async operation in a task will help avoid that problem. See the discussion on this thread and the recommended approach to prevent your UI thread from getting blocked.

    http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/8a91ffd9-67f8-4f01-8a52-25205c43db1b

    Is there anything generated in the output window that indicates any problem occurred? You can also instrument using OutputDebugString to quickly determine (from the debugger output window) how many files are created, written to if that doesn't address the issue your seeing.

    Thanks!


    David Lamb

    Tuesday, March 13, 2012 1:23 AM
    Moderator