Asked by:
Strange problem with asynchronous tasks

Question
-
This is the simple function.
task<void> ExtCommandReader::ReadHeader() { auto readBuf = ref new Buffer(static_cast<unsigned int>(3)); return task<IBuffer^>(m_conn->m_socket->InputStream->ReadAsync(readBuf, 3, InputStreamOptions::None)).then([=](task<IBuffer^> previousTask) { try { IBuffer^ ib = previousTask.get(); DataReader ^dr = DataReader::FromBuffer(ib); dr->UnicodeEncoding = UnicodeEncoding::Utf8; dr->ByteOrder = ByteOrder::BigEndian; unsigned int n = ib->Length; if (n < 3) throw ref new FailureException("failed to read ext command header"); requestCode = dr->ReadByte(); dataSize = dr->ReadUInt16(); } catch (Exception ^e) { getApp()->DebugPrint("ExtCommandReader::ReadHeader: Exception: " + e->Message); throw; } }); }
Now I have the dump file where the Access Violation exception is stored. The analysis shoed that the access violation occurred when invoking AsyncOperation::GetResults (within the then function above), and the AsyncOperation is NULL. All that lies within concurrency::tasks machinery and is pretty hard to read.
The AsyncOperation instance (that is NULL) is the member of task class. So, I am confused: why can it become zero?
Thank you
Iakov
Tuesday, November 5, 2013 12:48 PM
All replies
-
Why are you returning a task and then trying to work with the task's completion in the same function? What exactly does the caller of the function ExtCommandReader::ReadHeader() do? Does it try to extract data from the completion as well?
What happens when you do this and not return the task to the caller?
void ExtCommandReader::ReadHeader() { task<IBuffer^>(m_conn->m_socket->InputStream->ReadAsync(readBuf, 3, InputStreamOptions::None)).then([=](task<IBuffer^> previousTask) { ... remainder of the code.
Windows Store Developer Solutions, follow us on Twitter: @WSDevSol|| Want more solutions? See our blog
Tuesday, November 5, 2013 11:58 PMModerator -
Why are you returning a task and then trying to work with the task's completion in the same function?
Strange question. I believe that the construct task.then(...) is also a task and can be returned as a function value.
Also I believe that the code within then block is executed after the ReadAsync is completed and the data is ready for processing.
What exactly does the caller of the function ExtCommandReader::ReadHeader() do?
This is what the caller does:
task<void> ExtCommandReader::ReadExtensionCommand() { return ReadHeader().then([=]() { return m_conn->ReadBytes (dataSize); }).then([=](Array<byte> ^data) { return m_conn->ProcessExtensionCommand (requestCode, data); }); }
What happens when you do this and not return the task to the caller?
void ExtCommandReader::ReadHeader() { task<IBuffer^>(m_conn->m_socket->InputStream->ReadAsync(readBuf, 3, InputStreamOptions::None)).then([=](task<IBuffer^> previousTask) { ... remainder of the code.
If you mean code like this:
ReadHeader(); ReadData(); ProcessCommand();
this code will be incorrect, because ReadData needs DataSize that will be available only AFTER ReadHeader is completed. ProcessCommand needs actual data bytes as well. Without then(...) the ReadData will be executed asynchronously with respect to the ReadHeader, whereas I need it to be executed stricitly after.
Iakov
Wednesday, November 6, 2013 6:48 AM -
I also don't understand why you are exposing ExtCommandReader as a task. If you need to have cascading I/O tasks then the completion for reading the header would be ReadData task and it's completion would be a ProcessCommand task.Wednesday, November 6, 2013 9:42 PM
-
I also don't understand why you dictate me how I should write programs.
Is the program incorrect?
Is it prohibited to return tasks as function values?
Is it correct that if the program makes use of tasks, all of the tasks that make chain must be defined in the same function and cannot be passed across function boundaries - as return values, for example?
- Edited by Яков Wednesday, November 6, 2013 10:19 PM
Wednesday, November 6, 2013 10:18 PM -
Your approach is not wrong at all, you can certainly return a task as return values and chain them the way you are doing it. I just wanted to understand what the caller is doing with the returned task.
Since you are getting an Access Violation exception, can you share your dump file via Skydrive where you get this exception so that we can look?
Windows Store Developer Solutions, follow us on Twitter: @WSDevSol|| Want more solutions? See our blog
Thursday, November 7, 2013 12:05 AMModerator -
Here is the dump: http://sdrv.ms/15P4xtc.
Iakov
Friday, November 8, 2013 7:54 AM -
-
Here is the symbols file: http://sdrv.ms/15P4xtc
Friday, November 8, 2013 9:06 PM -
Here's the callstack leading to the exception:
0:003> r Last set context: eax=0226e8c0 ebx=0356dc50 ecx=00000000 edx=0226e8b8 esi=0c959c58 edi=0c959c58 eip=003f35cd esp=0226e8b0 ebp=0226e8cc iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206 SpecialistMetro!Windows::UI::Popups::IMessageDialog::Commands::get+0x3d: 003f35cd 8b01 mov eax,dword ptr [ecx] ds:0023:00000000=???????? 0:003> kp *** Stack trace for last set context - .thread/.cxr resets it ChildEBP RetAddr 0226e8cc 005e1df6 SpecialistMetro!Windows::UI::Popups::IMessageDialog::Commands::get(void)+0x3d 0226e918 005e1c67 SpecialistMetro!SpecialistMetro::ExtCommandReader::ReadHeader(void)+0x66 0226e998 00518a6a SpecialistMetro!SpecialistMetro::ExtCommandReader::ReadExtensionCommand(void)+0xc7 0226e9c8 00515750 SpecialistMetro!SpecialistMetro::ClientConnection::ReadExtensionCommand(void)+0x6a 0226ea34 005aea8a SpecialistMetro!<lambda_9b6875054dd5ea03fcd0666d21c0841e>::operator()(unsigned char msgType = 0x1e '')+0x120 ... ...
In the callstack above, your ReadHeaderFunction seems to be retrieving the MessageDialog::Commands property that leads to the Access Violation.
In the code you pasted above, I do not see any MessageDialog in your ReadHeader function, so where and how are you using the MessageDialog?
The exact source line that calls the MessageDialog::Commands is in extcommandreader.cpp at line 51.
Windows Store Developer Solutions, follow us on Twitter: @WSDevSol|| Want more solutions? See our blog
Friday, November 8, 2013 10:02 PMModerator -
Thank you for your help.
The ExtCommandReader::ReadHeader function text is posted in the initial message. Line 51 is the closing line of the then "operator":
task<void> ExtCommandReader::ReadHeader() { auto readBuf = ref new Buffer(static_cast<unsigned int>(3)); return task<IBuffer^>(...).then([=](task<IBuffer^> previousTask) { ... }); <--------- Line 51 }
Iakov
- Edited by Яков Saturday, November 9, 2013 6:40 AM
Saturday, November 9, 2013 6:37 AM