CLR via C # Reading Notes-26. Thread basics,
Preface
I have not written articles and shared records for these two months. I have been busy with project launching. But when I learned this, I felt uncomfortable when I stopped. The clr thread chapter has been read many times, the book has been read for hundreds of times. Today, let's talk about thread basics.
1. What is a process and the origin of the thread?
2. Thread overhead and online text Switching
3. Reasons for using threads
4. Thread Scheduling and priority
5. foreground and background threads
I. What is a process and the origin of the thread?
In the early years of the computer, OS had no thread concept. The whole system only ran one execution thread, including the operating system and application code. This means that long-running tasks will stop other tasks from running. In those 16-bit windows days, applications that print documents can easily "freeze" the entire machine, causing the OS and other applications to stop responding. In this case, the user can only create or restart the computer by Reset. All running applications will be terminated, resulting in the loss of the data being processed by the application.
Microsoft then designs a new OS kernel and decides to run each instance of the application in a process. The process is actually a collection of resources to be used by the instance of the application. Each process has a virtual address space to ensure that the code and data used in one process cannot be accessed by another process, and the process cannot access the kernel code and data of the OS. Therefore, applications cannot destroy other applications or OS itself, and the user experience becomes better.
It sounds good, but what about the CPU itself? What happens when an endless loop occurs in an application? If the machine has only one CPU, it will execute an endless loop. Although the data cannot be destroyed, the system may still stop responding. Microsoft's solution is thread. As a Windows concept, threads are responsible for virtualizing the CPU. Windows provides a dedicated thread (equivalent to a CPU) for each process ). The application code enters an endless loop. the processes associated with the code will be "Frozen", but other processes (they have their own threads) will not be frozen and they will continue to execute!
Ii. Thread overhead
1. thread kernel object)
OS allocates and initializes one of these data structures for each thread created in the system. The data structure contains a set of attributes that describe threads. The thread structure also contains the so-called thread context ). The context is the memory block that contains the set of CPU registers. For x86, x64, and arm cpu architectures, the thread context uses approximately 350, and bytes of memory respectively.
2. Fast thread environment (thread environment block, TEB)
TEB is the memory block allocated and initialized in user mode (the address space that application code can quickly access. TEB consumes one memory page (x86, x64, and 4 kb in arm cpu ). TEB contains the thread's head for exception handling ). Each try block entered by the thread inserts a node at the beginning of the chain. When the thread exits the try block, the node is deleted from the chain. In addition, TEB also contains the "locally stored thread" data of the thread, and some data structures used by GDI (Graphics Device Interface, graphical Device Interface) and OpenGL Graphics.
3. user-mode stack)
User Mode stack stores local variables and real parameters passed to the method. It also contains an address, indicating where the thread should be executed when the current method returns. By default, Windows allocates 1 MB of memory to the user mode stack of each thread.
4. kernel mode stack (kernel-mode-stack)
When the application code transmits real parameters to the kernel-mode function in the operating system, it also uses the kernel-mode stack. Due to security considerations, Windows copies any real parameters passed from the user mode code to the kernel from the user mode stack of the thread to the kernel mode stack of the thread. Once copied, the kernel can verify the value of the real parameter. Because the application code cannot access the kernel mode stack, the application cannot change the real parameter value after verification. The OS kernel code starts to process the copied value. In addition, the kernel calls its own internal method and uses the kernel mode stack to pass its own real parameters, local variables for storing functions, and storage return addresses.
4. Notification of DLL thread connection (attach) and thread separation (detach)
A policy of Windows is that when a thread is created in the process, all the DllMain methods of unmanaged DLL loaded in the process will be called and the DLL_THREAD_ATTACH flag will be passed to the method. Similarly, when the thread is terminated, all the DllMain methods of the unmanaged DLL in the process will be called and the DLL_THREAD_DETACH flag will be passed to the method. Some DLL must obtain these notifications to perform special initialization or (Resource) Cleanup operations for each thread created/destroyed in the process.
That is to say, when a thread is created and destroyed, this function in all DLL is called, seriously affecting the performance of creating and destroying threads in the process.
Context switching
A single CPU computer can only do one thing at a time. Windows must share the physical CPU among all threads (logical CPUs) in the system.
Windows allocates only one thread to one CPU at any time. The thread can run the length of a "time slice" (sometimes "quantity" or "range", that is, quantum. When the time slice expires, Windows switches the context to another thread. Each context switch requires windows to perform the following operations.
1. Save the value of the CPU register to a context structure inside the kernel object of the currently running thread.
2. Select a thread from the existing thread set for scheduling.
3. Load the value in the selected context structure to the CPU register.
After the context switch is complete, the CPU executes the selected thread until its time slice expires. Next context switch occurs. Windows performs context switching every 30 ms.
To build high-performance applications and components, try to avoid context switching.
Reducing the number of threads also significantly improves the performance of garbage collection.
Iii. Reasons for using threads
1. responsiveness (usually for Client GUI applications)
For example, in windows, each process provides its own thread to ensure that applications with an endless loop do not interfere with other applications. Similarly, some work can be handed over to some threads in the Client GUI application, so that the GUI thread can respond to user input sensitively.
2. Performance (for client and server applications)
Because each CPU in windows schedules one thread and multiple CPUs can concurrently execute these threads, executing multiple operations at the same time can improve performance.
Explicitly create your own thread if any of the following conditions are met
1. The thread must run at a non-normal thread priority.
2. The thread must be represented as a foreground thread to Prevent the application from terminating the task before the thread ends.
3. Computing restricted tasks need to run for a long time
4. The Thread to be started, and the abort method of the Thread may be called to terminate it in advance.
4. Thread Scheduling and priority
Each thread is assigned a priority from 0 (lowest) to 31 (highest.
As long as there is a thread with a scheduling priority of 31, the system will never set the priority to 0 ~ Any thread of 30 is allocated to the CPU. This situation becomes hunger.
When the system starts, a special zero page thread will be created ). This thread has a priority of 0 and is the only thread with a priority of 0 in the system. When no other thread needs to work, the zero-page thread clears all idle pages of the system RAM.
V. foreground and background threads
Using System; using System. collections. generic; using System. linq; using System. text; using System. threading; namespace ConsoleApplication2 {class Program {static void Main (string [] args) {// create a new Thread (foreground Thread by default) Thread t = new Thread (Worker ); // make the thread a background thread t. isBackground = true; // start thread t. start (); // If t is the foreground thread, the application will terminate after about 10 seconds. // If t is the background thread, the application will terminate the Console immediately. writeLine ("Returing from Main");} private static void Worker () {// simulate the Thread for 10 seconds. sleep (10000); // the following line of code displays the Console only when executed by a front-end thread. writeLine ("Returning from Worker ");}}}
View Code
The main Thread of the application and any Thread explicitly created by constructing a Thread object are foreground threads by default. Conversely, the thread pool thread is a background thread by default.
In addition, any thread created by native code that enters the Managed execution environment is marked as a background thread.
Tiandao rewards, the greatest truths are simple, insist.