Thread learning note 2: worker threads in thread pool

Keywords: C# Programming less Lambda

This note is excerpted from: https://www.cnblogs.com/zhili/archive/2012/07/18/ThreadPool.html Record the learning process for future reference.

I. thread pool Foundation

First of all, it takes a lot of time to create and destroy threads. Second, too many threads also waste memory resources. Therefore, creating too many threads through Thread class is detrimental to performance. To improve this

The thread pool is introduced in. NET.

The representation of thread pool image is a collection of threads used in an application (that is, the place where threads are put, so that threads can be managed in one place).

During CLR initialization, there are no threads in the thread pool. Internally, the thread pool maintains an operation request queue. When the application wants to perform an asynchronous operation, it calls a method to put a task into the thread pool

In the queue of, the thread pool code extracts the task from the queue and delegates the task to a thread pool thread for execution. When the thread pool thread completes the task, the thread will not be destroyed, but will return to the thread pool and wait for a response

A request. Because the thread is not destroyed, the performance loss caused by thread creation can be avoided.

MSDN statement:

"Thread pool is often used in server applications. Each new requirement is assigned to a thread in a thread pool, so that the requirement can be executed asynchronously without hindering the main thread or delaying the processing of subsequent requirements."

Note: threads created through the thread pool are background threads by default, and the priority is Normal by default.

2. Asynchronous implementation through worker threads of thread pool

2.1 method of creating worker thread

    public static bool QueueUserWorkItem (WaitCallback callback);

    public static bool QueueUserWorkItem(WaitCallback callback, Object state);

These two methods add a work item and an optional status data to the queue of thread pool, and then the two methods will return immediately.

The work item is actually a method identified by the callback parameter, which will be executed by the thread pool thread. The callback method written at the same time must match the System.Threading.WaitCallback delegate type, defined as:

    public delegate void WaitCallback(Object state);

The following shows how to implement asynchronous calls through thread pool threads:

    class Program
    {
        static void Main(string[] args)
        {
            #region Asynchronous implementation through worker threads of thread pool
            //Set the maximum number of worker threads in the thread pool to 1000, I/O The maximum number of threads is 1000.
            ThreadPool.SetMaxThreads(1000, 1000);
            Console.WriteLine("Main thread: queue an asynchronous method.");
            PrintMessage("Main thread start.");

            //Add the work item to the queue, and the thread pool will use the worker thread to execute the callback method.
            ThreadPool.QueueUserWorkItem(AsyncMethod);
            Console.Read();
            #endregion
        }

        /// <summary>
        /// Print thread pool information
        /// </summary>
        /// <param name="data"></param>
        private static void PrintMessage(string data)
        {
            // Get the number of worker threads available in the thread pool and I/O Number of threads
            ThreadPool.GetAvailableThreads(out int workThreadNumber, out int ioThreadNumber);

            Console.WriteLine("{0}\n CurrentThreadId is:{1}\n CurrentThread is background:{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is:{4}\n",
                data,
                Thread.CurrentThread.ManagedThreadId,
                Thread.CurrentThread.IsBackground.ToString(),
                workThreadNumber.ToString(),
                ioThreadNumber.ToString());
        }

        /// <summary>
        /// Asynchronous method: must match WaitCallback Entrust
        /// </summary>
        /// <param name="state"></param>
        private static void AsyncMethod(object state)
        {
            Thread.Sleep(1000);
            PrintMessage("Asynchoronous method.");
            Console.WriteLine("Asynchoronous thread has worked.");
        }
    }

The operation results are as follows:

From the result, we can see that there is one less worker thread available in the thread pool to execute the callback method.

The ThreadPool.QueueUserWorkItem(WaitCallback callback,Object state) method can pass the object object as a parameter to the callback function, using the method and

ThreadPool.QueueUserWorkItem(WaitCallback callback) is similar. It is not listed here.

2.2 collaborative cancellation

The. NET Framework provides a cancellation mode, which is collaborative. In order to cancel an operation, you must first create a system. Threading. Cancelationtokensource object.

The following code demonstrates the use of collaborative cancellation, which is mainly used to stop counting when the user clicks the Enter key on the console.

    class Program
    {
        static void Main(string[] args)
        {
            #region Collaborative cancellation
            ThreadPool.SetMaxThreads(1000, 1000);
            Console.WriteLine("Main thread run.");
            PrintMessage("Start");
            Run();
            Console.ReadKey();
            #endregion
        }

        /// <summary>
        /// Print thread pool information
        /// </summary>
        /// <param name="data"></param>
        private static void PrintMessage(string data)
        {
            //Get the number of worker threads available in the thread pool and I/O Number of threads
            ThreadPool.GetAvailableThreads(out int workThreadNumber, out int ioThreadNumber);

            Console.WriteLine("{0}\n CurrentThreadId is:{1}\n CurrentThread is background:{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is:{4}\n",
                data,
                Thread.CurrentThread.ManagedThreadId,
                Thread.CurrentThread.IsBackground.ToString(),
                workThreadNumber.ToString(),
                ioThreadNumber.ToString());
        }

        /// <summary>
        /// Run worker thread(Include collaborative cancellation)
        /// </summary>
        private static void Run()
        {
            CancellationTokenSource cts = new CancellationTokenSource();

            //Here is the use. Lambda The expression is written in the same way.
            //ThreadPool.QueueUserWorkItem(obj => Count(cts.Token, 1000));

            ThreadPool.QueueUserWorkItem(Callback, cts.Token);
            Console.WriteLine("Press enter key to cancel the operation.\n");
            Console.ReadLine();
            //Communicate cancellation request
            cts.Cancel();
        }

        /// <summary>
        /// Callback function
        /// </summary>
        /// <param name="state"></param>
        private static void Callback(object state)
        {
            Thread.Sleep(1000);
            PrintMessage("Asynchoronous method start.");
            CancellationToken token = (CancellationToken)state;
            Count(token, 1000);
        }

        /// <summary>
        /// Count
        /// </summary>
        /// <param name="token"></param>
        /// <param name="countTo"></param>
        private static void Count(CancellationToken token, int countTo)
        {
            for (int i = 1; i <= countTo; i++)
            {
                if (token.IsCancellationRequested)
                {
                    Console.WriteLine("Count is canceled.");
                    break;
                }

                Console.WriteLine(i);
                Thread.Sleep(300);
            }
            Console.WriteLine("Count has done.");
        }
    }

The operation results are as follows:

III. asynchronous implementation by delegation

Terminology involved -- asynchronous programming model:

APM asynchronous programming model

EAP event based asynchronous pattern

Task based asynchronous pattern

It's very convenient to start the worker thread by calling the QueueUserWorkItem method of ThreadPool, but the delegate WaitCallback points to a method with one parameter and no return value. If we are in actual operation

You need to have a return value, or you need to have multiple parameters, which is difficult to achieve in this way. In order to solve this problem, we can establish the working thread through delegation.

The following code demonstrates using delegation to implement asynchrony:

    class Program
    {
        //Using delegation to realize asynchrony is using asynchronous programming model APM. 
        private delegate string ThreadDelegate();

        static void Main(string[] args)
        {
            #region Asynchronous with delegation
            ThreadPool.SetMaxThreads(1000, 1000);
            PrintMessage("Main thread start.");

            //Instantiation delegation
            ThreadDelegate threadDelegate = new ThreadDelegate(AsyncMethod);
            //Asynchronous call delegate
            IAsyncResult result = threadDelegate.BeginInvoke(null, null);
            //Get results and print
            string returnData = threadDelegate.EndInvoke(result);
            Console.WriteLine(returnData);
            Console.ReadLine();
            #endregion
        }

        /// <summary>
        /// Asynchronous method
        /// </summary>
        /// <returns></returns>
        private static string AsyncMethod()
        {
            Thread.Sleep(1000);
            PrintMessage("Asynchoronous method.");
            return "Method has completed.";
        }
    }

The operation results are as follows:

IV. tasks

Similarly, tasks are introduced to solve the problem of restriction in ThreadPool.QueueUserWorkItem.

The following code demonstrates asynchronous implementation through tasks:

4.1 use tasks to achieve asynchrony

    class Program
    {
        static void Main(string[] args)
        {
            #region Asynchronous with tasks
            ThreadPool.SetMaxThreads(1000, 1000);
            PrintMessage("Main thread start.");
            //Call constructor to create Task object
            Task<int> task = new Task<int>(n => AsyncMethod((int)n), 10);

            //Start task 
            task.Start();
            //Wait for the task to complete
            task.Wait();
            Console.WriteLine("The method result is: " + task.Result);
            Console.ReadLine();
            #endregion
        }

        /// <summary>
        /// Asynchronous method
        /// </summary>
        /// <param name="n"></param>
        /// <returns></returns>
        private static int AsyncMethod(int n)
        {
            Thread.Sleep(1000);
            PrintMessage("Asynchoronous method.");

            int sum = 0;
            for (int i = 1; i < n; i++)
            {
                //Operation overflow check
                checked
                {
                    sum += i;
                }
            }

            return sum;
        }
    }

The operation results are as follows:

4.2 cancel task

If you want to cancel the task, you can also cancel it by cancelationtokensource object.

The following code shows how to cancel a task:

    class Program
    {
        static void Main(string[] args)
        {
            #region Cancel tasks
            ThreadPool.SetMaxThreads(1000, 1000);
            PrintMessage("Main thread start.");
            CancellationTokenSource cts = new CancellationTokenSource();

            //Call constructor to create Task Object, changing a CancellationToken Pass to Task Constructor to Task and CancellationToken Connect.
            Task<int> task = new Task<int>(n => AsyncMethod(cts.Token, (int)n), 10);

            //Start task 
            task.Start();
            //Delay cancel task
            Thread.Sleep(3000);

            //Cancel tasks
            cts.Cancel();
            Console.WriteLine("The method result is: " + task.Result);
            Console.ReadLine();
            #endregion
        }

        /// <summary>
        /// Asynchronous method
        /// </summary>
        /// <param name="ct"></param>
        /// <param name="n"></param>
        /// <returns></returns>
        private static int AsyncMethod(CancellationToken ct, int n)
        {
            Thread.Sleep(1000);
            PrintMessage("Asynchoronous method.");

            int sum = 0;
            try
            {
                for (int i = 1; i < n; i++)
                {
                    //When CancellationTokenSource Object call Cancel Method will cause OperationCanceledException Abnormal,
                    //By calling CancellationToken Of ThrowIfCancellationRequested Method to check whether the operation has been cancelled,
                    //This method and CancellationToken Of IsCancellationRequested Properties are similar.
                    ct.ThrowIfCancellationRequested();
                    Thread.Sleep(500);
                    //Operation overflow check
                    checked
                    {
                        sum += i;
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Exception is:" + e.GetType().Name);
                Console.WriteLine("Operation is canceled.");
            }

            return sum;
        }
    }

The operation results are as follows:

4.3 task factory

Asynchronous operation can also be realized through TaskFactory type of task factory.

 

    class Program
    {
        static void Main(string[] args)
        {
            #region Asynchronous with task factory
            ThreadPool.SetMaxThreads(1000, 1000);
            Task.Factory.StartNew(() => PrintMessage("Main thread."));
            Console.Read();
            #endregion
        }

        /// <summary>
        /// Print thread pool information
        /// </summary>
        /// <param name="data"></param>
        private static void PrintMessage(string data)
        {
            //Get the number of worker threads available in the thread pool and I/O Number of threads
            ThreadPool.GetAvailableThreads(out int workThreadNumber, out int ioThreadNumber);

            Console.WriteLine("{0}\n CurrentThreadId is:{1}\n CurrentThread is background:{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is:{4}\n",
                data,
                Thread.CurrentThread.ManagedThreadId,
                Thread.CurrentThread.IsBackground.ToString(),
                workThreadNumber.ToString(),
                ioThreadNumber.ToString());
        }
    }

The operation results are as follows:

 

Posted by dlkinsey85 on Mon, 09 Dec 2019 07:57:56 -0800