C # thread pool of multithreading article 1,

Source: Internet
Author: User

C # thread pool of multithreading article 1,

In the thread pool of C # multithreading, we will learn some common technologies for multi-threaded access to shared resources. We will learn the following knowledge points:

  • Call a delegate in the thread pool
  • Perform asynchronous operations in the thread pool
  • Thread Pool and degree of Parallelism
  • Enable cancel Option
  • Use wait handle and timeout
  • Use Timer
  • Use the BackgroundWorker component

In the previous "C # multithreading basics" and "C # multithreading thread synchronization", we learned how to create a thread and how to use multithreading to work collaboratively. In this article, another scenario is that we need to create many asynchronous operations that take a short time to complete some work. We know that creating a thread is very expensive. Therefore, it is not appropriate to create a thread for every asynchronous operation that takes a very short time.

We can use the thread pool to solve the above problem. We can allocate a certain number of threads in the thread pool. Whenever we need a thread, we only need to obtain a thread in the thread pool, instead of creating a new thread, when we use a thread, we only need to re-place the thread into the thread pool.

We can use the System. Threading. ThreadPool type to use the thread pool. The thread pool is managed by the Common Language Runtime (CLR), which means that each CLR can have only one thread pool instance. The ThreadPool type has a "QueueUserWorkItem" static method. This static method receives a delegate, which represents a user-defined asynchronous operation. When this method is called, the delegate enters the internal queue. At this time, if there is no thread in the thread pool, a new working thread will be created, and then the delegate (the first) put in the queue.

If we place a new operation to the thread pool after the previous operation is completed, we may reuse the worker thread of the previous operation. If the number of threads in the thread pool reaches the upper limit when we place a new operation, the new operation will wait in the queue until there is a working thread available in the thread pool.

It should be noted that we try to place some operations that require less time to complete in the thread pool, rather than placing operations that require a large amount of time to complete, at the same time, do not block working threads. If this is not the case, the working thread becomes very busy and cannot respond to user operations. It also causes performance problems and debugging errors that are difficult to debug.

In addition, the worker threads in the thread pool are all background threads, which means that when all foreground threads are executed, the background threads will be stopped.

In this article, we will learn how to use the thread pool to perform asynchronous operations, how to cancel an operation, and how to prevent a thread from running for a long time.

1. Call the delegate in the thread pool

In this section, we will learn how to asynchronously execute a delegate in the thread pool. To demonstrate how to call a delegate in the thread pool, perform the following steps:

1. Use Visual Studio 2015 to create a new console application.

2. Double-click to open the "Program. cs" file and write the code as follows:

 1 using System; 2 using System.Threading; 3 using static System.Console; 4 using static System.Threading.Thread; 5  6 namespace Recipe01 7 { 8     class Program 9     {10         private delegate string RunOnThreadPool(out int threadId);11 12         private static string Test(out int threadId)13         {14             WriteLine("Starting...");15             WriteLine($"Is thread pool thread: {CurrentThread.IsThreadPoolThread}");16             Sleep(TimeSpan.FromSeconds(2));17             threadId = CurrentThread.ManagedThreadId;18             return $"Thread pool worker thread id was : {threadId}";19         }20 21         private static  void Callback(IAsyncResult ar)22         {23             WriteLine("Starting a callback...");24             WriteLine($"State passed to a callback: {ar.AsyncState}");25             WriteLine($"Is thread pool thread: {CurrentThread.IsThreadPoolThread}");26             WriteLine($"Thread pool worker thread id: {CurrentThread.ManagedThreadId}");27         }28 29         static void Main(string[] args)30         {31             int threadId = 0;32             var t = new Thread(() => Test(out threadId));33             t.Start();34             t.Join();35             WriteLine($"Thread id: {threadId}");36 37             RunOnThreadPool poolDelegate = Test;38             IAsyncResult r = poolDelegate.BeginInvoke(out threadId, Callback, "a delegate asynchronous call");39             r.AsyncWaitHandle.WaitOne();40             string result = poolDelegate.EndInvoke(out threadId, r);41             WriteLine($"Thread pool worker thread id: {threadId}");42             WriteLine(result);43 44             Sleep(TimeSpan.FromSeconds(2));45         }46     }47 }

3. Run the console application. The running effect is shown in:

In the code of Row 3, we used the old method to create a thread, start it, and wait for it to be executed. Because the thread constructor only receives the delegate method without the returned value, we pass a lambda expression to it. In this expression, we call the "Test" method. In the "Test" method, we use the "Thread. CurrentThread. IsThreadPoolThread" attribute value to determine whether the Thread is from the Thread pool. We also use the "CurrentThread. ManagedThreadId" attribute value to print the thread ID that runs the current code.

In the code of Row 3, a delegate is defined. the return value of the delegate method is a string type and an output parameter of the integer type is received.

In the code of Row 3, we assign the Test method to the poolDelegate delegate, and use the ininvoke method of the delegate to run the Test method pointed to by the delegate in the code of Line 3 ). BeginInvoke receives a callback method, which is called after the asynchronous operation is complete. The third parameter of BeginInvoke is a user-defined State passed to the callback method. This state is usually used to distinguish an asynchronous call. We use the "IAsyncResult" interface to save the return value of the "BeginInvoke" method.

The BeginInvoke method returns immediately, which allows us to continue executing the next code in the thread that calls the BeginInvoke method while the worker thread in the thread pool executes.

In the code of Row 3, we can use the return value of the BeginInvoke method and call the EndInvoke method to obtain the asynchronous operation result.

Note: The 39th line of code is not required. If we comment out this line of code, the program continues to run successfully because the "EndInvoke" method will always wait until the asynchronous operation is completed. Another advantage of calling the "EndInvoke" method is that any unhandled exceptions in the work thread will be thrown to the call thread.

If 44th lines of code are commented out, the Callback method "Callback" will not be executed because the main thread has ended and all background threads will be stopped.

2. Perform asynchronous operations in the thread pool

In this section, we will learn how to perform asynchronous operations in the thread pool. The specific steps are as follows:

1. Use Visual Studio 2015 to create a new console application.

2. Double-click to open the "Program. cs" file and write the code as follows:

 1 using System; 2 using System.Threading; 3 using static System.Console; 4 using static System.Threading.Thread; 5  6 namespace Recipe02 7 { 8     class Program 9     {10         private static void AsyncOperation(object state)11         {12             WriteLine($"Operation state: {state ?? "(null)"}");13             WriteLine($"Worker thread id: {CurrentThread.ManagedThreadId}");14             Sleep(TimeSpan.FromSeconds(2));15         }16 17         static void Main(string[] args)18         {19             const int x = 1;20             const int y = 2;21             const string lambdaState = "lambda state 2";22 23             ThreadPool.QueueUserWorkItem(AsyncOperation);24             Sleep(TimeSpan.FromSeconds(2));25 26             ThreadPool.QueueUserWorkItem(AsyncOperation, "async state");27             Sleep(TimeSpan.FromSeconds(2));28 29             ThreadPool.QueueUserWorkItem(state =>30             {31                 WriteLine($"Operation state: {state}");32                 WriteLine($"Worker thread id: {CurrentThread.ManagedThreadId}");33                 Sleep(TimeSpan.FromSeconds(2));34             }, "lambda state");35 36             ThreadPool.QueueUserWorkItem(state =>37            {38                WriteLine($"Operation state: {x + y}, {lambdaState}");39                WriteLine($"Worker thread id: {CurrentThread.ManagedThreadId}");40                Sleep(TimeSpan.FromSeconds(2));41            }, "lambda state");42 43             Sleep(TimeSpan.FromSeconds(2));44         }45     }46 }

3. Run the console application. The running effect may be different each time, as shown in:

In 10th ~ In the 15 lines of code, we define an "AsyncOperation" method with object type parameters, and then in the 23rd lines of code, we use the "QueueUserWorkItem" static method of ThreadPool to execute the "AsyncOperation" method in the thread pool.

In the code of Row 3, we once again used the "QueueUserWorkItem" static method to execute the "AsyncOperation" method in the thread pool, but this time we passed the state parameter to the "AsyncOperation" method.

At lines 24th and 27th, we blocked the main thread for 2 seconds to reuse the worker thread in the thread pool. If we comment out the two lines of code, the thread ID of the working thread will be different in most cases.

In 29th ~ In the 41-line code, we demonstrated how to use lambda expressions to perform asynchronous operations in the thread pool. Please analyze the results by yourself.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.