I have a C function FsReadStream
that does some asynchronous work and takes a callback. When done, it calls the callback using the QueueUserWorkItem windows function.
I am trying to call this function from managed code (c#) using the async/await pattern. So I do the following
- Construct a
Task
object passing the constructor a lambda that returns the result. - Construct a callback that runs this task using the
RunSynchronously
method - Call the asynchronous native function, passing in the callback
- Return the task object to the caller
My code looks something like this
/// Reads into the buffer as many bytes as the buffer size
public Task<ReadResult> ReadAsync(byte[] buffer)
{
GCHandle pinnedBuffer = GCHandle.Alloc(buffer, GCHandleType.Pinned);
IntPtr bytesToRead = Marshal.AllocHGlobal(sizeof(long));
Marshal.WriteInt64(bytesToRead, buffer.Length);
FsAsyncInfo asyncInfo = new FsAsyncInfo();
ReadResult readResult = new ReadResult();
Task<ReadResult> readCompletionTask = new Task<ReadResult>(() => { return readResult; });
TaskScheduler scheduler = TaskScheduler.FromCurrentSynchronizationContext();
asyncInfo.Callback = (int status) =>
{
readResult.ErrorCode = status;
readResult.BytesRead = (int)Marshal.ReadInt64(bytesToRead);
readCompletionTask.RunSynchronously(scheduler);
pinnedBuffer.Free();
Marshal.FreeHGlobal(bytesToRead);
};
// Call asynchronous native method
NativeMethods.FsReadStream(
pinnedBuffer.AddrOfPinnedObject(),
bytesToRead,
ref asyncInfo);
return readCompletionTask;
}
and I call it like this
ReadResult readResult = await ReadAsync(data);
I have two questions
- How to make the code that runs after the call to
await ReadAsync
run on the same thread as the callback? Currently, I see it runs on a different thread even though I am callingreadCompletionTask.RunSynchronously
. I am running this code under ASP.NET and IIS. - Does the native
QueueUserWorkItem
function use the same threadpool as the managed ThreadPool.QueueUserWorkItem method? My opinion was that it should, and therefore it should be possible for the managedTaskScheduler
to schedule tasks on the native callback thread.