The operating system manages the execution of the program through threads, and when the operating system runs a program, the operating system assigns a process to the program that is ready to run to manage the various resources required by the program. Among these resources, a thread data structure called the main thread is included to manage the execution state of the program.
Under the Windows operating system, the data structure of a thread contains the following content:
1, the core object of the thread: mainly contains the current register state of the thread, when the operating system scheduling this thread to start running, the state of the register will be loaded into the CPU, rebuild the execution environment of the thread, when the thread is dispatched, the last register state is re-saved here, Used when an execution has been prepared.
2. Thread Environment block (thread environment block,ted): is a piece of memory in user mode that contains the head of the thread's exception handling chain. In addition, the local storage data for threads (thread local Storage) also exists here.
3, user-mode stack: The user program's local variables and parameters are used by the stack, by default, Windows will be allocated 1M of space for the user-mode stack.
4. Kernel-mode stack: the stack used to access the operating system.
In a preemptive multitasking environment, at a specific time, the CPU is scheduled to execute a thread into the CPU, which will run at most one time slice, and when the time slice expires, the operating system will dispatch the thread out of the CPU and another thread into the CPU. We usually call this operation a context switch.
At each context switch, Windows performs the following steps:
- Saves the current CPU register value to the currently running thread data structure, which is the thread core object within it.
- Select the next thread that is ready to run, and if the thread is in a different process, you must first switch the virtual address space.
- Loads the CPU register state of the ready-to-run thread into the CPU.
The common language runtime CLR (Common Language Runtime) is the environment in which a. NET program runs, which is responsible for resource management and ensures the necessary separation between the application and the underlying operating system.
In the. NET environment, threads in the CLR need to do the actual work through the operating system's threads, in the present case. NET directly maps the threads in the CLR to the operating system's threads for processing and scheduling, so that each thread we create consumes more than 1M of memory space. However, the future threads in the CLR do not necessarily correspond exactly to the threads in the operating system. By creating logical threads under the CLR environment, we might create more resource-efficient threads, allowing a large number of CLR threads to work on a small number of operating system threads.
Definition of a thread
Within a single-CPU system (time slice), the CPU can only run a single thread, and the order of operation depends on the priority level of the thread. If the thread fails to complete execution at the unit time, the system will persist the state information of the threads to the thread's local memory (TLS) so that it can resume execution the next time it executes. And multithreading is only the illusion of the system, it in multiple units of time to switch multiple threads, because the switching frequency and unit time is very short, so multithreading is considered to run concurrently.
The proper use of multithreading can improve the performance of the system, such as: When the system requests large-capacity data using multi-threading, the data output to the asynchronous thread, so that the main thread to maintain its stability to deal with other problems. However, it is important to note that because the CPU takes a lot of time to switch on the thread, excessive use of multithreading can lead to degraded performance.
1. Common classes in System.Threading namespaces
There are several ways to build multithreaded applications within the System.Threading namespace, where ThreadPool and thread are most commonly used in multithreaded development, and a CLR thread pool is specifically set up in. NET to manage the running of threads. This CLR thread pool is managed by the ThreadPool class, and thread is the most straightforward way to manage threads.
Class |
Description |
AutoResetEvent |
Notifies the waiting thread that an event has occurred |
ManualResetEvent |
Notifies the waiting thread that an event has occurred |
Interlocked |
Provides atomic operations for variables shared by multiple threads |
Monitor |
Provides a mechanism for synchronizing access to objects |
Mutex |
A synchronization primitive that can also be used for inter-process synchronization |
Thread |
Create and control a thread, set its priority, and get its state |
ThreadPool |
Provides a thread pool that can be used to send work items, handle asynchronous I/O, wait on behalf of other threads, and handle timers |
WaitHandle |
Encapsulates an operating system-specific object that waits for exclusive access to a shared resource |
Readwriterlock |
Read/write Lock |
Semaphore |
Control the number of threads accessed |
Second, the priority of the thread
To facilitate thread management, the thread has a priority, which is used to determine which thread takes precedence, and the priority attribute in the thread object.
The priority levels are from low to high, respectively:
Priority level |
Description |
Lowest |
Thread can be scheduled after threads with any other priority |
BelowNormal |
You can schedule thread to be behind threads with the Normal priority, before lines with Lowest precedence |
Normal |
The default value. You can schedule thread to be placed after threads that have abovenormal priority, before lines with BelowNormal precedence |
AboveNormal |
You can schedule thread to be placed after threads that have highest priority, before lines with the Normal priority |
Highest |
Thread can be scheduled before threads with any other priority |
Let's look at a priority example:
Class program { static void Main (string[] args) { //Create a new 3 threads and set their respective priority thread T1 = new Thread (Run); T1. priority = Threadpriority.lowest; Thread t2 = new Thread (Run); T2. priority = Threadpriority.normal; thread t3 = new Thread (Run); T3. priority = Threadpriority.highest; Call T1 in order from low to high priority . Start (); T2. Start (); T3. Start (); Console.readkey (); } public static void Run () { Console.WriteLine ("My priority is:" + Thread.CurrentThread.Priority);} }
Look at the output:
Note that threads are executed in the order of precedence.
Three, Common properties
Common Properties |
Description |
CurrentThread |
Gets the currently running thread |
IsAlive |
Gets a value that indicates the execution state of the current thread |
IsBackground |
Gets or sets a value that indicates whether a thread is a background thread and the background thread exits with the foreground thread closing |
Isthreadpoolthread |
Gets a value that indicates whether the thread belongs to the managed thread pool |
Managedthreadid |
Gets the unique identifier of the current managed thread |
Name |
Gets or sets the name of the thread |
Priority |
Gets or sets a value that indicates the scheduling priority of the thread |
ThreadState |
Gets a value that contains the state of the current thread |
Managedthreadid is a unique identifier for the confirmation thread, and in most cases the program uses Thread.managedthreadid to identify the thread. cannot be passed by name because name is just a simple property that can be arbitrarily changed and cannot be guaranteed to be non-repeatable.
Examples of common properties:
Class program { static void Main (string[] args) { //Create a new 3 threads and set their respective priority thread T1 = new Thread (Run); T1. priority = Threadpriority.normal; T1. Start (); Console.readkey (); } public static void Run () { Thread t1 = thread.currentthread; A static property that gets the thread that currently executes this line of code Console.WriteLine ("My priority is:" + t1. priority); Console.WriteLine ("Am I still executing:" + t1. IsAlive); Console.WriteLine ("is a background thread:" + t1.) IsBackground); Console.WriteLine ("Is Thread pool threads:" + t1. Isthreadpoolthread); Console.WriteLine ("Thread Unique identifier:" + T1.) Managedthreadid); Console.WriteLine ("My Name is:" + t1. Name); Console.WriteLine ("My Status is:" + t1. threadstate); } }
The output is as follows:
1, the difference between the foreground thread and the background thread
We see that there is a property called background thread, non-background thread called the foreground thread,Thread.Start () Start line Cheng think the foreground thread, the main thread that is created when starting the program must be the foreground thread. The application must wait until all foreground threads have finished executing before uninstalling. When IsBackground is set to true, it is a background thread, and when the main thread executes, it is unloaded directly, regardless of whether the background thread has finished executing.
The settings for foreground and background threads must be set before the thread is started and cannot be set after the threads are started.
The thread created by thread is the foreground thread, which is a background thread in the thread pool.
Class program { static void Main (string[] args) { thread t1 = new Thread (Run); T1. IsBackground = true; Set as Background thread t1. Start (); Console.WriteLine ("Wait for you, background thread!"); Note that this does not console.readxxx (); Let the console execute automatically shut down } public static void Run () { thread.sleep ( ); Console.WriteLine ("Background thread is executing! "); } }
The difference between a foreground thread and a background thread is as follows: The above example cannot be illustrated with a picture, briefly stating what happened. When T1 is set to the foreground thread, the console window is closed after 5 seconds. If T1 is set to a background thread, the window is instantly closed.
2, the state of ThreadState
There are several values for ThreadState:
Thread state |
Description |
Aborted |
Thread has stopped |
AbortRequested |
The thread's Thread.Abort () method has been called, but the thread has not stopped |
Background |
Threads are executed in the background, related to property thread.isbackground |
Running |
Thread is running correctly |
Stopped |
Thread has been stopped |
stoprequested |
Thread is being asked to stop |
Suspended |
The thread has been suspended (in this state, it can be rerun by calling the Resume () method) |
suspendrequested |
Thread is asking to be suspended but not responding |
Unstarted |
Not calling Thread.Start () to start the run of the thread |
WaitSleepJoin |
Thread is blocked because it calls wait (), Sleep (), or join () |
The threads switch between the above states in the following ways:
The thread you just created is in a state that is ready to run, but not yet running, called the ready state. Under the operation of the operating system, this thread can enter (runing) running state. The running state of the thread may be switched out of the CPU by the operating system due to the time-slice run-up, called suspended (paused) state, or it may be converted to the blocked (blocking) state by waiting for other higher-priority tasks when the time slice is not exhausted. A thread that is in a blocking state can be re-entered in the running state at any time because it is scheduled again. The thread may also enter sleep state through the sleep method, which can be scheduled to run again after the sleep time expires. A running thread may also be actively terminated, either directly or by the end of the operating system due to the completion of the task.
Iv. methods
Method |
Description |
Abort |
Terminating a thread |
GetDomain |
The application domain in which the current thread is running |
Getdomainid |
Unique application domain identifier |
Interrupt |
Break a thread in the WaitSleepJoin thread state |
Join |
Blocks the calling thread until a thread terminates |
ResetAbort |
Cancels the Abort requested for the current thread |
Sleep |
Blocks the current thread for the specified number of milliseconds |
SpinWait |
Causes a thread to wait for the amount of time defined by the iterations parameter |
Start |
To start a thread to execute on a schedule |
1. Join Serial execution
Join, serial execution, equivalent to the Async:false inside Ajax
Class program { static void Main (string[] args) { thread t1 = new Thread (Run); T1. Name = "T1"; T1. Start (); T1. Join (); After waiting for the T1 to execute, the main thread executes again, the relationship between the threads is serial, non-parallel Console.WriteLine ("The main thread executes this?"). "); Console.readkey (); } public static void Run () { Console.WriteLine ("Thread" + Thread.CurrentThread.Name + "start execution!"); Thread.Sleep (the); Console.WriteLine ("Thread" + Thread.CurrentThread.Name + "execution complete!"); } }
Output:
2, Interrupt and Abort
Interrupt and Abort: These two keywords are used to force the termination of the thread, but there is a difference between the two.
1, Interrupt: Throw is the threadinterruptedexception exception.
Abort: The ThreadAbortException exception is thrown.
2, Interrupt: If the worker thread is terminated, it can only be managed once, the next time the worker's sleep is not in the pipeline, the equivalent of a contine operation. If the thread is in a sleep state, skipping this state through Interrypt can also achieve a wake-up effect.
Abort: This is equivalent to a break operation and the worker thread is completely stopped. Of course, you have also called Thread.resetabort () to cancel termination in catch (ThreadAbortException ex) {...}.
Class Program {static void Main (string[] args) {thread T1 = new Thread (Run); T1. Start (); When Interrup, the thread has entered a for loop, and after the first break, the second loop can no longer stop T1. Interrupt (); T1. Join (); Console.WriteLine ("============================================================"); Thread t2 = new Thread (Run); T2. Start (); The purpose of stopping 1 seconds is to let the thread T2 start, otherwise T2 has stopped directly thread.sleep (1000) without starting; Terminate the thread directly, the thread is terminated, nature cannot output what! T2. Abort (); Console.readkey (); } static void Run () {for (int i = 1; I <= 5; i++) {try {//Continuous sleep 5 times thread.sleep (2000); Console.WriteLine ("First" + i + "sleep!"); } catch (Exception e) {Console.WriteLine ("the" + i + "time sleep is interrupted!" + "" + e.message); } } } }
Output:
3. Suspend and Resume (use with caution)
Thread.Suspend () and Thread.Resume () are old methods that already exist in Framework1.0, and they can suspend and resume threads, respectively. But these two methods have been explicitly rejected in the Framework2.0. This is because once a thread occupies an existing resource, and then uses suspend () to keep the thread in a suspended state for a long time, it causes a deadlock when other threads invoke those resources! Therefore, the use of these two methods should be avoided in the absence of necessary conditions. In MSDN, both methods have also been marked as obsolete.
V. ThreadStart COMMISSION
ThreadStart generated is not managed by the thread pool.
To start a thread through a ThreadStart delegate:
Class program { static void Main (string[] args) { Console.WriteLine ("Main thread ID is:" + THREAD.CURRENTTHREAD.MANAGEDTHREADID); Message message = new Message (); Thread thread = new Thread (The new ThreadStart (message). ShowMessage)); Thread. Start (); Console.WriteLine ("Doing sth ..."); Console.WriteLine ("Main thread work done!"); Console.readkey (); } public class Message {public void ShowMessage () { string Message = string. Format ("Async thread ID: {0}", Thread.CurrentThread.ManagedThreadId); Console.WriteLine (message); for (int i = 0; i < i++) {thread.sleep) ; Console.WriteLine ("Asynchronous thread is currently looping execution to" + i);}}}}
Output:
Vi. Parameterizedthreadstart Commission
Parameterizethreadstart delegates are very similar to ThreadStart delegates, but Parameterizedthreadstart delegates are oriented with parametric methods. Note that the argument to the Parameterizedthreadstart method is object.
Class Person {public person (string name, int age) {this. Name = Name;this. Age = age; } public string Name {get; Set } public int Age {get; set;} } class Program {static void Main (string[] args) {//integer as parameter for (int i = 0; I & Lt 2; i++) {Thread t = new Thread (new Parameterizedthreadstart (Run)); T.start (i); } Console.WriteLine ("The main thread has finished executing! "); Custom type as parameter person p1 = new Person ("Guan Yu", 22); person P2 = new Person ("Zhang Fei", 21); thread T1 = new Thread (new Parameterizedthreadstart (RUNP)); T1. Start (p1); Thread t2 = new Thread (new Parameterizedthreadstart (RUNP)); T2. Start (p2); Console.readkey (); } public static void Run (Object i) {Thread.Sleep (50); Console.WriteLine ("Line path comes in parameters are:" + i.tostring ()); } public static void RUnP (Object o) {thread.sleep (50); Person p = o as person; Console.WriteLine (P.name + p.age); } }
Output:
Vii. Commission of TimerCallback
The TimerCallback delegate is dedicated to the operation of the timer, which allows us to define a timed task that repeats the call after the specified interval. The actual type is the same as the Parameterizedthreadstart delegate.
The constructor of the timer class is defined as follows:
Public Timmer (TimerCallback callback,object state,long Duetime,long period)
- Callback represents a delegate that executes when a time arrives, and the method represented by the delegate must conform to the definition of the delegate timercallback.
- State indicates the parameters passed when the timer delegate is called.
- Duttime represents the time, in milliseconds, to delay from creating a timer to the first call.
- Period represents the time interval, in milliseconds, between each invocation after the timer starts.
example, use TimerCallback to output one time every second:
Class program { static void Main (string[] args) { System.Threading.Timer clock = new System.Threading.Timer (ConsoleApplication1.Program.ShowTime, NULL, 0, +); Console.readkey (); } public static void ShowTime (object userData) { Console.WriteLine (DateTime.Now.ToString ()); } }
The output is as follows:
Thread preliminary Understanding-< First >