In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article mainly introduces the example analysis of c # multithreaded programming, which has a certain reference value. Interested friends can refer to it. I hope you will gain a lot after reading this article.
1. Necessary knowledge of multithreaded programming
1.1 the concept of processes and threads
When we open an application, the operating system will assign a process ID to the application, for example, open QQ, and you will see the QQ.exe process in the process tab of the task manager, as shown below:
A process can be understood as an area of memory that contains some resources, and the operating system divides its work into different units through the process. An application can correspond to multiple processes.
A thread is an independent execution unit in a process. for the operating system, it makes the application work by scheduling threads. A process contains at least one thread, and we make that thread the main thread. The relationship between the thread and the process can be understood as: the thread is the execution unit of the process, and the operating system makes the application work by scheduling the thread, while the process is the container of the thread, which is created by the operating system. The thread is created in the specific execution process.
1.2 scheduling of threads
It seems to be mentioned in the operating system book that "Windows is a preemptive multithreaded operating system." The reason for saying this is preemptive because a thread can be preempted at any time to schedule another thread. The operating system assigns a priority of 0-31 to each thread, and assigns high-priority threads to CPU execution first.
Windows supports seven relative thread priorities: Idle, Lowest, BelowNormal, Normal, AboveNormal, Highest, and Time-Critical. Where Normal is the default thread priority. A program can change the priority of a thread by setting the Priority property of Thread, which is of type ThreadPriority enumeration and whose members include Lowest, BelowNormal, Normal, AboveNormal, and Highest. CLR has reserved two priorities for itself, Idle and Time-Critical.
1.3 threads are also divided into front and background.
Threads can be divided into foreground threads and background threads. In a process, when all foreground threads stop running, CLR forces the termination of all running background threads, which are terminated directly without throwing any exceptions. The main thread will always be the foreground thread. We can use the Tread class to create a foreground thread.
Using System;using System.Threading;namespace multithreading 1 {internal class Program {private static void Main (string [] args) {var backThread = new Thread (Worker); backThread.IsBackground = true; backThread.Start (); Console.WriteLine ("exit from main thread"); Console.ReadKey ();} private static void Worker () {Thread.Sleep (1000) Console.WriteLine ("exit from background thread");}
The above code first creates a thread object through the Thread class, and then indicates that the thread is a background thread by setting the IsBackground property. If this property is not set, the default is the foreground thread. Then the method of Start is called, and the background thread executes the code of the Worker function. So there are two threads in this program, one is the main thread running the Main function, and the other is the background thread running the Worker thread. Since CLR terminates the background thread unconditionally after the foreground thread finishes execution, in the previous code, if the background thread is started, the main thread will continue to run. After the main thread finishes execution, CLR finds that the main thread ends, terminates the background thread, and then causes the entire application to finish running, so the Console statement in the Worker function will not be executed. So the result of the above code does not run the Console statement in the Worker function.
You can use the method of the Join function to ensure that the main thread does not start running until the background thread has finished executing.
Using System;using System.Threading;namespace multithreading 1 {internal class Program {private static void Main (string [] args) {var backThread = new Thread (Worker); backThread.IsBackground = true; backThread.Start (); backThread.Join (); Console.WriteLine ("exit from main thread"); Console.ReadKey ();} private static void Worker () {Thread.Sleep (1000) Console.WriteLine ("exit from background thread");}
The above code calls the Join function to ensure that the main thread will not run until the background thread ends.
If your thread executes a method that requires arguments, you need to use new Thread's overloaded constructor Thread (ParameterizedThreadStart).
Using System;using System.Threading;namespace multithreading 1 {internal class Program {private static void Main (string [] args) {var backThread = new Thread (new ParameterizedThreadStart (Worker)); backThread.IsBackground = true; backThread.Start ("Helius"); backThread.Join (); Console.WriteLine ("exit from main thread"); Console.ReadKey () } private static void Worker (object data) {Thread.Sleep (1000); Console.WriteLine ($"the parameter passed in is {data.ToString ()}");}
The execution result is:
2. The container of thread-thread pool
Previously, we have manually created threads through the Thead class, but thread creation and destruction can take a lot of time, and such manual operations will result in performance losses. Therefore, in order to avoid the loss caused by manually creating threads through Thread, .NET introduced a thread pool mechanism.
2.1 Thread Pool
Thread pool is used to store the collection of threads to be used in the application, which can be understood as a place to store threads. This centralized storage method is conducive to thread management.
When CLR is initialized, there are no threads in the thread pool. Internally, the thread pool maintains an operation request queue, and when the application wants to perform an asynchronous operation, it needs to call the QueueUserWorkItem method to add the corresponding task to the thread pool's request queue. The code implemented by the thread pool is extracted from the queue and delegated to threads in the thread pool to execute. If there are no idle threads in the thread pool, the thread pool also creates a new thread to perform the extracted task. When a thread pool thread completes a task, the thread is not destroyed, but returns to the thread pool and waits for another request. Because threads are not destroyed, performance loss is avoided. Remember that the threads in the thread pool are all background threads, and the default level is Normal.
2.2 Multithreading through thread pools
To use threads in the thread pool, you need to call the static method ThreadPool.QueueUserWorkItem to specify the method to be called by the thread, which has two overloaded versions:
Public static bool QueueUserWorkItem (WaitCallback callBack)
Public static bool QueueUserWorkItem (WaitCallback callback,Object state)
These two methods are used to add a work first and an optional state data to the thread pool queue. These two methods then return immediately. Here is an example to demonstrate how to use thread pools to implement multithreaded programming.
Using System;using System.Threading;namespace multithreading 2 {class Program {static void Main (string [] args) {Console.WriteLine ($"main thread ID= {Thread.CurrentThread.ManagedThreadId}"); ThreadPool.QueueUserWorkItem (CallBackWorkItem); ThreadPool.QueueUserWorkItem (CallBackWorkItem, "work"); Thread.Sleep (3000); Console.WriteLine ("main thread exit"); Console.ReadKey () } private static void CallBackWorkItem (object state) {Console.WriteLine ("Thread pool thread starts execution"); if (state! = null) {Console.WriteLine ($"Thread pool thread ID= {Thread.CurrentThread.ManagedThreadId}, passed in parameter {state.ToString ()}");} else {Console.WriteLine ($"Thread pool thread ID= {Thread.CurrentThread.ManagedThreadId}") }
The result is:
2.3 Collaborative cancellation of thread pool threads
The .NET Framework provides a mode of canceling operations, which is collaborative. To cancel an operation, you must create a System.Threading.CancellationTokenSource object. Let's use the code to demonstrate:
Using System;using System.Threading;namespace multithreading 3 {internal class Program {private static void Main (string [] args) {Console.WriteLine ("main thread running"); var cts = new CancellationTokenSource (); ThreadPool.QueueUserWorkItem (Callback, cts.Token); Console.WriteLine ("press enter to cancel operation"); Console.Read (); cts.Cancel (); Console.ReadKey () } private static void Callback (object state) {var token = (CancellationToken) state; Console.WriteLine ("start counting"); Count (token, 1000);} private static void Count (CancellationToken token, int count) {for (var I = 0; I)
< count; i++) { if (token.IsCancellationRequested) { Console.WriteLine("计数取消"); return; } Console.WriteLine($"计数为:{i}"); Thread.Sleep(300); } Console.WriteLine("计数完成"); } }} 结果为: 3、线程同步 线程同步计数是指多线程程序中,为了保证后者线程,只有等待前者线程完成之后才能继续执行。这就好比生活中排队买票,在前面的人没买到票之前,后面的人必须等待。 3.1 多线程程序中存在的隐患 多线程可能同时去访问一个共享资源,这将损坏资源中所保存的数据。这种情况下,只能采用线程同步技术。 3.2 使用监视器对象实现线程同步 监视器对象(Monitor)能够确保线程拥有对共享资源的互斥访问权,C#通过lock关键字来提供简化的语法。 using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;using System.Threading.Tasks;namespace 线程同步{ class Program { private static int tickets = 100; static object globalObj=new object(); static void Main(string[] args) { Thread thread1=new Thread(SaleTicketThread1); Thread thread2=new Thread(SaleTicketThread2); thread1.Start(); thread2.Start(); Console.ReadKey(); } private static void SaleTicketThread2() { while (true) { try { Monitor.Enter(globalObj); Thread.Sleep(1); if (tickets >0) {Console.WriteLine ($"Thread 2 invoice: {tickets--}");} else {break;}} catch (Exception) {throw;} finally {Monitor.Exit (globalObj) } private static void SaleTicketThread1 () {while (true) {try {Monitor.Enter (globalObj); Thread.Sleep (1); if (tickets > 0) {Console.WriteLine ($"Thread 1 invoice: {tickets--}") } else {break;}} catch (Exception) {throw;} finally {Monitor.Exit (globalObj);}
In the above code, an additional static global variable globalObj is defined and passed as a parameter to the Enter method. Objects that use Monitor locking need to be reference types, not value types. Because when the value type is passed to the Enter, it is boxed into a separate poison incense and then passed to the Enter method, and when the variable is passed to the Exit method, a separate reference object is created. At this point, unlike the object passed to the Enter method and the object passed to the Exit method, Monitor will throw a SynchronizationLockException exception.
3.3 problems in thread synchronization technology
(1) it is tedious to use. It cannot be left out to surround data accessed by multiple threads at the same time with extra code.
(2) using thread synchronization will affect the performance of the program. Because it takes time to acquire and release synchronous locks, and CPU also coordinates when deciding which thread acquires the lock first. All this extra work can have an impact on performance.
(3) Thread synchronization allows only one thread to access resources at a time, which leads to thread congestion. Then the system will create more threads, and CPU will have to take on more onerous scheduling work. This process has an impact on performance.
Here is the code to explain the performance gap:
Using System;using System.Collections.Generic;using System.Diagnostics;using System.Linq;using System.Text;using System.Threading;using System.Threading.Tasks;namespace thread synchronization 2 {class Program {static void Main (string [] args) {int x = 0; const int iterationNumber = 50000 000; Stopwatch stopwatch=Stopwatch.StartNew (); for (int I = 0; I < iterationNumber; iTunes +) {x synchronization + } Console.WriteLine ($"time spent without locks: {stopwatch.ElapsedMilliseconds} ms"); stopwatch.Restart (); for (int I = 0; I < iterationNumber; iTunes +) {Interlocked.Increment (ref x);} Console.WriteLine ($"time spent using locks: {stopwatch.ElapsedMilliseconds} ms"); Console.ReadKey ();}
Execution result:
Thank you for reading this article carefully. I hope the article "sample Analysis of c # multithreaded programming" shared by the editor will be helpful to everyone. At the same time, I also hope that you will support and pay attention to the industry information channel. More related knowledge is waiting for you to learn!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.