locked
The problem of writing the data in buffer to a file in time

    Question

  • I read the HTTPClient example in Scenario2 and try to modify something.

    http://code.msdn.microsoft.com/windowsapps/HttpClient-sample-55700664

    What I want to do is save the data in buffer to a file each time.

    That is, when I download a file from server and read a chunk of data from the HTTP response, I want to save the chunk of data in buffer to a file in time.

    My way is use dataWriter to wirte :

    task<void> Scenario2::Scenario2ReadData(Windows::Storage::StorageFile^ file, DataWriter^ dataWriter)
    {
         return httpRequest.ReadAsync(readBuffer, 0, readBuffer->Capacity).then([this, file, dataWriter](task<void> readTask)
    	{
                    readTask.get();
    		
    		dataWriter->WriteBuffer(readBuffer);
    
    		task<unsigned int>(dataWriter->StoreAsync()).then([dataWriter, this](task<unsigned int> t){
    
    			return dataWriter->FlushAsync();
    
    		}).then([this](task<bool> t){
    
    
    			try{
    				t.get();
    
    			}catch(Exception^ e){
    
    
    			}
    
    		});
    		return httpRequest.IsResponseComplete() ? readTask : Scenario2ReadData(file,dataWriter);
    	}, task_continuation_context::use_current());
    }

    However, dataWriter write the data to a file after few times ,it has the exception:

    First-chance exception at 0x75A14B32 in HttpClient.exe: Microsoft C++ exception: Platform::ChangedStateException ^ at memory location 0x02DACB44. HRESULT:0x8000000C

    The seems that it's the dataWriter->StoreAsync() problem.

    Does anyone can help me?

    Thank you so much.


    • Edited by Mandy1205 Wednesday, September 19, 2012 2:45 AM
    Wednesday, September 19, 2012 2:43 AM

Answers

  • You should never capture types like this by reference ([&dataWriter]) as suggested in a continuation of an async operation.  Doing so is a recipe for memory corruption and/or subtle hard to find bugs.  When the continuation runs, the stack for the original method will have unwound and the continuation will touch whatever address the hat had on the original methods stack (which by this time is LIKELY a random location on the stack that has a meaningless value).  Hat types are reference types to begin with.  You aren't, as suggested in the prior response, changing a copy of the data writer.

    The reason that you get this error is that not every underlying WinRT stream supports multiple outstanding asynchronous writes simultaneously.  It is likely that what is happening here is a timeline like what follows:

    • Someone calls Scenario2ReadData
    • The HTTP request completes
    • The asynchronous file write is scheduled (StoreAsync)
    • The recursive call for a reading the response happens (the : Scenario2ReadData) or another call happens
    • The HTTP request completes
    • A second asynchronous file write is scheduled (StoreAsync)

    The second request will wind up throwing this exception as I do not believe that the file streams that you are writing to support multiple outstanding asynchronous requests.

    You can step through and verify this; however -- if the problem here is the recursive call and the continued response read, there are several different ways to think about/solve this:

    • Implement your own strategy (e.g.: queueing) for the writes to your file
    • Modify the task chain such that the subsequent httpRequest.ReadAsync doesn't happen until after the file write happens (e.g.: recurse in the .then of the write).  This has the implication that the next http read will not happen until after the file write (which may or may not be okay).
    • Modify the task chain such that subsequent writes don't happen until the previous file write happens (e.g.: stash the previous write task and have your Write/StoreAsync act as a continuation on that).
    Wednesday, September 19, 2012 5:22 PM

All replies

  • Hello,

    I think you should binding the dataWriter in Lambda express. If you do not binding it, the lambda express only change a copy of datawirter.

    return httpRequest.ReadAsync(readBuffer, 0, readBuffer->Capacity).then([this, file, &dataWriter](task<void> readTask)

    task<unsigned int>(dataWriter->StoreAsync()).then([&dataWriter, this](task<unsigned int> t){

    Best regards,
    Jesse


    Jesse Jiang [MSFT]
    MSDN Community Support | Feedback to us


    • Edited by Jesse Jiang Wednesday, September 19, 2012 10:39 AM
    Wednesday, September 19, 2012 10:39 AM
  • You should never capture types like this by reference ([&dataWriter]) as suggested in a continuation of an async operation.  Doing so is a recipe for memory corruption and/or subtle hard to find bugs.  When the continuation runs, the stack for the original method will have unwound and the continuation will touch whatever address the hat had on the original methods stack (which by this time is LIKELY a random location on the stack that has a meaningless value).  Hat types are reference types to begin with.  You aren't, as suggested in the prior response, changing a copy of the data writer.

    The reason that you get this error is that not every underlying WinRT stream supports multiple outstanding asynchronous writes simultaneously.  It is likely that what is happening here is a timeline like what follows:

    • Someone calls Scenario2ReadData
    • The HTTP request completes
    • The asynchronous file write is scheduled (StoreAsync)
    • The recursive call for a reading the response happens (the : Scenario2ReadData) or another call happens
    • The HTTP request completes
    • A second asynchronous file write is scheduled (StoreAsync)

    The second request will wind up throwing this exception as I do not believe that the file streams that you are writing to support multiple outstanding asynchronous requests.

    You can step through and verify this; however -- if the problem here is the recursive call and the continued response read, there are several different ways to think about/solve this:

    • Implement your own strategy (e.g.: queueing) for the writes to your file
    • Modify the task chain such that the subsequent httpRequest.ReadAsync doesn't happen until after the file write happens (e.g.: recurse in the .then of the write).  This has the implication that the next http read will not happen until after the file write (which may or may not be okay).
    • Modify the task chain such that subsequent writes don't happen until the previous file write happens (e.g.: stash the previous write task and have your Write/StoreAsync act as a continuation on that).
    Wednesday, September 19, 2012 5:22 PM