I have the following WCF contract:
[ServiceContract(Namespace = \"http://abc/Services/AdminService\")]
public interface IAdminService
{
[OperationContrac
First, you'd need to add TaskContinuationOptions.ExecuteSynchronously
, to make sure the continuation callback is called on the same thread the async IO operation has been finalized:
return miniAdminService.GetServiceVersionAsync().ContinueWith(t =>
{
if (t.Exception != null)
{
// The Admin Service seems to be unavailable
}
else
{
// The Admin Service is available
}
}, TaskContinuationOptions.ExecuteSynchronously);
Apparently, there is no API in .NET to tell if the thread is a IOCP pool thread. You can only tell if the thread is a thread pool thread (Thread.CurrentThread.IsThreadPoolThread
), which is true
for IOCP threads too.
In Win32, an IOCP thread pool is created with CreateIoCompletionPort API, but I couldn't find a Win32 API to check if the thread belongs to such pool, either.
So, here is a bit contrived example to check this theory in practice, using HtppClient
as the test vehicle. First, we make sure all non-IOCP threads have populated the ThreadStatic
variable s_mark
with -1
. Then we initiate an IO-bound operation and check s_mark
on thread where the IO-bound operation gets completed:
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication_22465346
{
public class Program
{
[ThreadStatic]
static volatile int s_mark;
// Main
public static void Main(string[] args)
{
const int THREADS = 50;
// init the thread pool
ThreadPool.SetMaxThreads(
workerThreads: THREADS, completionPortThreads: THREADS);
ThreadPool.SetMinThreads(
workerThreads: THREADS, completionPortThreads: THREADS);
// populate s_max for non-IOCP threads
for (int i = 0; i < THREADS; i++)
{
ThreadPool.QueueUserWorkItem(_ =>
{
s_mark = -1;
Thread.Sleep(1000);
});
}
Thread.Sleep(2000);
// non-IOCP test
Task.Run(() =>
{
// by now all non-IOCP threads have s_mark == -1
Console.WriteLine("Task.Run, s_mark: " + s_mark);
Console.WriteLine("IsThreadPoolThread: " + Thread.CurrentThread.IsThreadPoolThread);
}).Wait();
// IOCP test
var httpClient = new HttpClient();
httpClient.GetStringAsync("http://example.com").ContinueWith(t =>
{
// all IOCP threads have s_mark == 0
Console.WriteLine("GetStringAsync.ContinueWith, s_mark: " + s_mark);
Console.WriteLine("IsThreadPoolThread: " + Thread.CurrentThread.IsThreadPoolThread);
}, TaskContinuationOptions.ExecuteSynchronously).Wait();
Console.WriteLine("Enter to exit...");
Console.ReadLine();
}
}
}
The output:
Task.Run, s_mark: -1 IsThreadPoolThread: True GetStringAsync.ContinueWith, s_mark: 0 IsThreadPoolThread: True Enter to exit...
I think this might be enough evidence to confirm the theory that an IO-bound continuation does happen on an IOCP thread.
A good read, related: "There Is No Thread" by Stephen Cleary.