Read Catalogue
- Code download
- First, the creation and start of a thread
- Second, pass the data to a thread
- Third, named thread
- Iv. foreground thread and background thread
- Five, Thread priority
- Vi. Exception Handling
Original address: C # multithreaded Tour (2)--Create and start threads
C # multithreaded Tour directory:
C # multithreaded Tour (1)--Introduction and basic concepts
C # multithreaded Tour (2)--Create and start threads
C # multithreaded Tour (3)--thread pool
C # multithreaded Tour (4)--Synchronization Essence
......
C # multithreaded Tour (2)--Create and start threads
Back to the top of the code download
Thread_ Blog Park _cnblogs_jackson0714.zip
code example for the first ~ third article:
Back to TopFirst, the creation and start of a thread
In the first article, threads are created using The constructor of the thread class, passing a threadstart Delegate to implement where the thread starts executing. Here is the definition of ThreadStart:
summary:// represents the method that executes on a system.threading.thread.[ ComVisible (true)]public delegate void ThreadStart ();
Call a start method, and then set it to start running. The thread will run until this method returns, and the thread ends.
Here is an example of creating a ThreadStart delegate using the extended C # syntax : 2.1_threadstart
1 class ThreadTest 2 {3 static void Main () 4 {5 thread t = new Thread (new ThreadStart (Go)); 6 T.start (); 7 Go (); 8 Console.readkey (); 9 }10 static void Go () one { Console.WriteLine ("Hello!"); }14}
In this example, thethread T executes go (), which basically calls the Go () method with the main line, and the result is a two-time close Hello.
A thread can be easily created by specifying a method group, which is then inferred from C # ThreadStart delegate: 2.2_thread
1 class Program 2 {3 static void Main (string[] args) 4 {5 thread t = new Thread (Go); 6 T.start (); 7 Go (); 8 Console.readkey (); 9 }10 one static void Go () { Console.WriteLine ("Go"); }15}
Another simpler way is to use lambda expressions or Anonymous methods:2.3_lambaexpression
static void Main (string[] args) { thread t = new Thread (() =>console.writeline ("Go")); T.start (); Console.readkey ();}
Go back to the top second, pass the data to a thread 1. Using lambda to pass a data
The simplest way to pass a parameter to the target method of a thread is to execute a lambda expression that invokes a method and passes the desired argument to the method.
2.4_passingdatatoathread
static void Main (string[] args) { thread t = new Thread (() = Print ("A")); T.start (); Console.readkey ();} static void Print (String message) { Console.WriteLine (message);}
2. Passing Multiple parameters
In this way, you can pass any number of arguments to this method. You can even wrap the entire implementation in a multi-statement Lambda :
2.5_passingdatatoathread
New Thread (() =>{ Console.WriteLine ("a"); Console.WriteLine ("B");}). Start ();
You can also simply do the same with the anonymous method in C # 2.0:
New Thread (Delegate () { Console.WriteLine ("a"); Console.WriteLine ("B");}). Start ();
3. Transfer parameters using Thread.Start
Another way is to pass a parameter to the Thread 's Start method:
2.6_passingdatatoathread_threadstart
static void Main (string[] args) { thread t = new Thread (Print); T.start ("A"); Console.readkey ();} static void Print (object messageobj) { String message = (string) messageobj;//must be converted Console.WriteLine ( message);}
This works because the constructor of Thread is overloaded and accepts any of the following two types of delegates:
summary:// represents the method that executes on a system.threading.thread.[ ComVisible (true)]public delegate void ThreadStart ();//summary:// represents the method that executes on a system.thr Eading. thread.////parameters:// obj://An object this contains data for the thread procedure.[ ComVisible (false)]public delegate void Parameterizedthreadstart (object obj);
This Parameterizedthreadstart only allows to receive one parameter. And because its type is object, it usually needs to be converted.
4.Lambda expressions and capture variables
As you can see from the example above, a lambda type is most used to pass data to a thread. However, you must be very careful to accidentally modify the capture variable after starting the thread, because these variables are shared. For example, the following:
2.7_lbdaexpressionsandcapturedvariables
for (int i =0;i<10;i++) { new Thread (() = Console.Write (i)). Start ();}
This output is indeterminate and the following is a typical case:
The problem here is that the variable i points to the same memory address when the for loop executes. Therefore, when each thread calls Console.Write , the value of I may change while the thread is running.
The solution is to use a temporary variable:
2.8_lambdaexpressionsandcapturedvariables_solution
for (int i = 0; i < ten; i++) { int temp = i; New Thread (() = Console.Write (temp)). Start ();}
The variable temp is in a different block of memory in each iteration of the loop. So each thread captures a different memory location, and there's no problem. We can explain the problem in the previous code:
2.9_passingdata_temporaryvariable
String text = "A"; Thread A = new Thread (() = Console.WriteLine (text)); text = "B"; Thread B = new Thread (() = Console.WriteLine (text)); A.start (); B.start ();
Because two lambda expressions capture the same value of text , B is printed two times.
Back to top three, named thread
Each thread has a Name property that you can use conveniently for debugging. When the thread displays the Threads Window and Debug loaction toolbar inside the Visual Statudio, the thread's Name Properties are particularly useful. You can only set the name of the thread once, and then try to change it to throw an exception message.
The static Thread.CurrentThread property represents the currently executing thread.
In the following example 2.10_namingthread, we set the name of the main thread:
static void Main (string[] args) { Thread.CurrentThread.Name = "Main Thread"; Thread t = new thread (Go); T.name = "Worker Thread"; T.start (); Go (); Console.readkey ();} static void Go () { Console.WriteLine ("Go! The current thread is {0} ", Thread.CurrentThread.Name);}
Back to top four, foreground thread and background thread
By default, you show yourself that the thread you created is the foreground thread. The foreground thread keeps the application alive as long as any one of them is running, and the latter thread is not. Once all the foreground threads are complete, the application ends and any running background thread terminates immediately.
The status of a thread's foreground / background is not associated with its priority and the configured execution time.
You can use the thread's isbackgroud property to query or change the background state of a thread.
Here is an example: 2.11_prioritytest
static void Main (string[] args) { thread t = new Thread (() = Console.readkey ()); if (args. Length > 0)//If the main method does not pass in Parameters { //set thread as background thread, wait for user input. //Because the main thread is in T. Start () terminates after execution, //So the background thread T terminates immediately after the main thread exits, and the application ends. T.isbackground = true; } T.start ();}
If the parameter is passed in when the program calls, the thread created is the foreground thread, and then waits for the user to enter it.
Also, if the main thread exits, the application will not exit because the foreground thread T does not exit.
On the other hand, if the main method passes in a parameter, the created thread is set to the background thread. When the main thread exits, the application exits immediately.
When a process terminates in this manner, the finally statement block inside any background thread execution stack will be circumvented.
This is a problem if your thread uses a finally (or using) statement block to perform cleanup work such as freeing resources or deleting temporary files. To avoid this, you can display the wait for the background thread to exit the application.
There are two ways to achieve this:
- If you create this thread yourself, you can call the Join method on this thread .
- If you use a thread pool, you can use an event to wait for the thread to be processed.
In both cases, you need to specify a timeout, so you can end a thread that refuses to complete for some reason. This is your alternative exit strategy: At the end, you want your application to shut down without requiring the user to remove it from Task Manager.
If a user forces the end of a. NET process by using Task Manager , all threads terminate as if they were a background thread. This is the observed behavior, so it will vary depending on the version of the CLR and the operating system.
Foreground threads do not need to be treated this way, but you must be careful to avoid bugs that can cause threads to end . One of the usual reasons that the application does not exit correctly is that there is an active foreground thread that is still alive.
Back to top five, thread priority
The priority of a thread determines how much of the execution time it can get relative to other threads in the operating system, and the following is the level of thread precedence:
summary:// Specifies the scheduling priority of a system.threading.thread.[ Serializable][comvisible (True)]public enum threadpriority{ Lowest = 0, belownormal = 1, Normal = 2, AboveNormal = 3, Highest = 4,}
Thread priority is important when multithreading is active at the same time.
Note: When you increase the thread priority, you need to be very careful, which can cause problems for other threads to access the hungry state of the resource.
When you raise the priority of a thread, it does not perform real-time work because it is limited by the application's process precedence. In order to perform real-time work, you must also prioritize processes by using the system.diagnostices process class:
using (Process p = process.getcurrentprocess ()) { p.priorityclass = Processpriorityclass.high;}
Processpriorityclass.high is actually the highest priority: real-time. Setting a process priority to a real-time state will cause other threads to get no CPU time slices. If your application unexpectedly enters an infinite loop state, you may even find that the operation is locked and only the power key can save you. For this reason,high is often the best choice for real-time applications.
If your real-time application has a user interface, increasing the priority of the program will make the refresh interface take up expensive CPU time and make the whole system run slowly (especially when the UI is complex). Reducing the primary thread priority and raising the priority of the process ensures that the real-time thread is not preempted by the interface redraw, but does not address the lack of CPU access to other processes , because the operating system will always allocate a disproportionate amount of resources to the process. An ideal solution is to allow real-time threads and user interfaces to run in different processes with different priorities, communicating through remote and memory mapped files. Even if the process priority is increased, there is a limit to how well the system needs to handle hard work in a managed environment. In addition, hidden problems will be introduced by automatic garbage collection, the operating system will encounter new challenges, even unmanaged code, the use of dedicated hardware or special real-time platform, it will be the best solution.
Back to top six, exception handling
The thread created within any try/catch/finally statement block scope is not associated with the statement block when the thread starts.
Consider the following procedure:
Reference Example: 2.12_exceptionhandling
static void Main (string[] args) { try { new Thread (Go). Start (); } catch (Exception ex) { Console.WriteLine ("Exception"); } Console.readkey ();} static void Go () { throw null;}
The Try/catch declaration is invalid in this example, and the newly created thread will be blocked by an unhandled NullReferenceException . This behavior is good when you consider that each thread has a separate execution path.
The improved method is to move the exception handler to the Go () method:
Reference Example: 2.13_exceptionhandling_remedy
Class program{ static void Main (string[] args) { new Thread (Go). Start (); Console.readkey (); } static void Go () { Try { throw null; } catch (Exception ex) { Console.WriteLine (ex. Message);}}}
You need to add a exception handler to all thread entry methods in your application , just as you did in the primary thread. An unhandled thread will cause the entire application to close and a bad window will pop up.
When writing this exception handling statement block, you may rarely overlook this problem, typically, you might log exception details, and then perhaps display a window that allows the user to automatically submit the information to your on the Web server. Then you may turn off the application - because this error destroys the state of the program. Then, the overhead is that the user may lose his recent work, such as open documents.
For WPF and WinForm applications, the global exception handling event ( Application.dispatcherunhandlerexception and application.threadexception) will only detect the main UI The exception that is thrown on the thread. You still have to handle the thread's exception manually.
AppDomain.CurrentDomain.UnhandledException can detect any unhandled exception, but cannot block the application from shutting down.
However, in some cases you do not need to handle exceptions on the thread because the . NET Framework has done this for you. Here's what's not mentioned:
Asynchronous delegates
Backgroudworker
The Task Parallel Library (conditions apply)
Dry share: The beginning and creation of a detailed thread