Share via


ThreadPool.UnsafeQueueNativeOverlapped

CLR’s thread pool has two pools of threads. The first pool is used by ThreadPool.QueueUserWorkItem. The second pool is an IoCompletionPort thread pool used by ThreadPool.BindHandle and ThreadPool.UnsafeQueueNativeOverlapped.

ThreadPool.BindHandle is used by CLR to implement asynchronous IO. For example, FileStream uses it to implement BeginRead/BeginWrite. Developers can take advantage of it too. We will talk about that in a separate article.

ThreadPool.UnsafeQueueNativeOverlapped can be used to queue a non IO work item to the IoCompletionPort thread pool, just like ThreadPool.QueueUserWorkItem.

Why will you want to use ThreadPool.UnsafeQueueNativeOverlapped instead of ThreadPool.QueueUserWorkItem?

In our development, we discover an inefficiency of ThreadPool.QueueUserWorkItem. If we have some alternate high and low number of work items, some of the threads may do busy waiting, artificially increase the CPU usage of our application.

If you have the same pattern, and you have observed high CPU usage when it should not, you can try ThreadPool.UnsafeQueueNativeOverlapped.

The following is an example how to ThreadPool.UnsafeQueueNativeOverlapped.

using System;

using System.Runtime.InteropServices;

using System.Threading;

namespace UQNO

{

    internal class AsyncHelper

    {

        WaitCallback callback;

        object state;

        internal AsyncHelper(WaitCallback callback, object state)

        {

            this.callback = callback;

            this.state = state;

        }

        unsafe internal void Callback(uint errorCode, uint numBytes, NativeOverlapped* _overlapped)

        {

            try

            {

                this.callback(this.state);

            }

            finally

            {

                Overlapped.Free(_overlapped);

            }

        }

    }

    class Program

    {

        static void Main(string[] args)

        {

            ManualResetEvent wait = new ManualResetEvent(false);

            WaitCallback callback = delegate(object state)

            {

                Console.WriteLine("callback is executed in thread id {0} name {1}", Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.Name);

                ManualResetEvent _wait = (ManualResetEvent)state;

                _wait.Set();

            };

            AsyncHelper ah = new AsyncHelper(callback, wait);

            unsafe

            {

                Overlapped overlapped = new Overlapped();

                NativeOverlapped* pOverlapped = overlapped.Pack(ah.Callback, null);

                ThreadPool.UnsafeQueueNativeOverlapped(pOverlapped);

                wait.WaitOne();

            }

        }

    }

}

Comments