C # Multithreading practices-creating and starting to use

Source: Internet
Author: User

Threads are created with the thread class, and the ThreadStart delegate is used to indicate where the method begins to run. ThreadStart's statement is as follows:

public delegate void ThreadStart ();

After the Start method is called, the thread begins to run until the method it invokes returns to the end.

Class ThreadTest {  static void Main () {    thread t = new Thread (new ThreadStart (Go));    T.start ();       Go ();          }  static void Go () {Console.WriteLine ("hello!");}

A thread can be created more conveniently through the short syntax of the delegate in C #:

static void Main () {  Thread t = new Thread (Go);    You do not need to explicitly declare the use of ThreadStart  T.start ();  ...} static void Go () {...} In this case, ThreadStart is automatically inferred by the compiler:

Another quick way is to use an anonymous method to start a thread

static void Main () {  thread t = new Thread (delegate () {Console.WriteLine ("hello!");});  T.start ();}

The thread has a IsAlive property that is true until the thread ends until the start () is called. Once a thread is finished, it cannot start over again.

Passing data into ThreadStart

If you want better regions to separate the output of each thread, such as having one of the threads output uppercase letters. Consider passing in a status word to go to complete the task, and you cannot use the ThreadStart delegate because it does not accept parameters. However, the NET Framework defines another version of the delegate called Parameterizedthreadstart, which can receive a separate object type parameter, and the delegate declaration is as follows:

public delegate void Parameterizedthreadstart (object obj);

Examples are as follows:

Class Threaddemo {  static void Main () {    thread t = new Thread (Go);//compiler automatically infers    T.start (true);             = = Go (True)     go (false);  }  static void Go (object uppercase)  {    bool upper = (bool) uppercase;    Console.WriteLine (upper? "Hello!": "hello!");  }

In the entire example, the compiler automatically infers the Parameterizedthreadstart delegate, because the go method receives a separate object argument, as in this case:

Thread t = new Thread (new Parameterizedthreadstart (Go)); T.start (true);

The Parameterizedthreadstart feature is that we need to boxing the type we want (here is bool) before using it, and it can only receive one parameter.

An alternative is to use an anonymous method to invoke an ordinary method as follows:

static void Main () {  Thread t = new Thread (delegate () {WRITETEXT ("Hello");});  T.start ();} static void WriteText (string text) {Console.WriteLine (text);}

The advantage is that the target method (here, WRITETEXT) can receive any number of arguments, and there is no boxing operation. However, it is necessary to put an external variable into the anonymous method, as follows:

static void Main () {  string text = "Before";  Thread t = new Thread (delegate () {WRITETEXT (text);});  Text = "after";  T.start ();} static void WriteText (string text) {Console.WriteLine (text);}

The anonymous method has a strange phenomenon: when an external variable is modified by a subsequent code, the thread may unintentionally interact with the external variable. On the other hand, intentional interaction (usually through a field) can also be used in this way! Once the thread has started running, the external variable is best handled as read-only-unless someone is willing to use the appropriate lock.

Another common way is to pass the method of an object instance to a thread instead of a static method, and the properties of the object instance can tell the thread what to do, such as the following example of overriding the previous section:

Class threaddemo{  bool Upper;    static void Main ()  {    Threaddemo Instance1 = new Threaddemo ();    Instance1.upper = true;    Thread t = new Thread (Instance1. Go);    T.start ();    Threaddemo Instance2 = new Threaddemo ();    Instance2. Go ();        Main thread--run Upper=false  }    void Go () {Console.WriteLine (upper? "Hello!": "hello!"); }

naming threads

A thread can be named by its Name property, which is very useful for debugging: You can print the name of the thread with Console.WriteLine, and Microsoft Visual Studio can display the name of the threads in the location of the Debug toolbar. The name of the thread can be set at any time--but only once, and renaming throws an exception.

The main thread of the program can also be named, the main thread in the following example is named by CurrentThread:

Class Threadnaming {  static void Main ()   {    Thread.CurrentThread.Name = "main";    Thread worker = new Thread (Go);    Worker. Name = "worker";    Worker. Start ();    Go ();  }  static void Go ()  {    Console.WriteLine ("Hello from" + Thread.CurrentThread.Name);}  }

Foreground and background threads

The line Cheng thinks of the foreground thread, which means that any foreground thread running will keep the program alive. C # also supports background threads, and when all foreground threads end, they do not maintain the program's survival.

Changing a thread from the foreground to the background does not change its priority and status in the CPU coordinator in any way.

The IsBackground property of the thread controls its front and back state, as in the following example:

Class Prioritytest {  static void Main (string[] args)   {    thread worker = new Thread (delegate () {Console.re Adline (); });    if (args. Length > 0) worker. IsBackground = true;    Worker. Start ();  }}

If the program is called without any arguments, the worker thread is the foreground thread and will wait for the ReadLine statement to wait for the user's trigger return, during which the main thread exits, but the program remains running because a foreground thread is still alive. On the other hand if a parameter is passed into main (), the worker thread is assigned a background thread, and when the main thread ends the program exits immediately, terminating the ReadLine. This termination of the background thread makes any final operation evasive, which is not appropriate. The good way is to explicitly wait for any background worker thread to finish before ending the program, possibly with a timeout (mostly with thread.join). If for some reason a worker cannot be completed, it can try to terminate it, if it fails, then discards the thread, allowing it to die with the process. (Recording is a problem, but it is meaningful in this scenario)

It is beneficial to have a background worker thread, and the most straightforward reason is that it may have a final say when the program is closed, along with a foreground thread that does not die, guaranteeing the program's normal exit. Discarding a foreground worker thread is more risky, especially for Windows Forms programs, because the program exits (at least for the user) until the end of the main thread, but its process is still running. It disappears from the application bar, but it can be found in the Windows Task Manager process bar. Unless it is manually found and ended, it will continue to consume resources and may prevent a new instance from restarting or affecting its attributes.

The common reason for program failure exits is that there is a "forgotten" foreground thread.

Thread Priority

The thread's Priority property determines how much execution time the thread threads has for other threads that are active on the same process, and the following are the levels:

Enum ThreadPriority {Lowest, BelowNormal, Normal, AboveNormal, highest}

Priority is only useful if multiple threads are active at the same time.

Setting a thread to a higher priority does not mean that it can do real-time work because it is limited to the process level of the program. To perform real-time work, you must elevate the level of the process under the System.Diagnostics namespace, as follows:

Process.getcurrentprocess (). PriorityClass = Processpriorityclass.high;

Processpriorityclass.high is actually the highest priority in a time slice: Realtime. Set the process level to realtime notify the operating system: You don't want your process to be preempted. If your program enters an accidental dead loop, you can expect that the operating system is locked out, except for shutting down nothing can save you! Based on this, high is generally considered the highest useful process level.

If a real-time program has a user interface, raising the level of the process is not good, because when the user interface UI is too complex, the interface update consumes too much CPU time and slows down the entire computer. Reducing the level of the main thread, raising the level of the process, and ensuring that the real-time thread does not refresh the interface does not prevent the computer from getting slower because the operating system will still dial out too much CPU to the entire process. The ideal solution is to enable real-time work and user interfaces to run in different processes (with different priorities), communicate through remoting or shared memory, and share memory with p/invoking in the Win32 API. (Can search to see createfilemapping and mapviewoffile)

Exception handling

Any thread creates a range of try/catch/finally blocks, and when a thread starts executing it no longer has any relationship with it. Consider the following procedure:

public static void Main () {Try  {   new Thread (Go). Start (); } catch (Exception ex) {   //will not get abnormal   Console.WriteLine ("exception!") in this;}  static void Go () {throw null;}}

  这里try/catch语句一点用也没有,新创建的线程将引发NullReferenceException异常。当你考虑到每个线程有独立的执行路径的时候,便知道这行为是有道理的。补救方法是在线程处理的方法内加入他们自己的异常处理。

public static void Main () {   new Thread (Go). Start ();}  static void Go () {  try {    ...    throw null;      This exception will be captured below    ...  }  catch (Exception ex) {logs    the Exception log, and or notifies another thread that we have an    error ...  }

Starting with. NET 2.0, unhandled exceptions within any thread will cause the entire program to close, which means that ignoring the exception is no longer an option. So in order to avoid a program crash caused by an unhandled exception, the Try/catch block needs to appear within the method each thread enters, at least in the product program. For Windows Forms programmers who often use global exception handling, this can be a bit of a hassle, like this:

Using system;using system.threading;using System.Windows.Forms;  Static class Program {  static void Main () {    application.threadexception + = HandleError;    Application.Run (New MainForm ());  }    static void HandleError (object sender, Threadexceptioneventargs e) {    log exception or exit program or continue running ...  }}

The Application.ThreadException event is triggered when an exception is thrown, in a way that Windows information (such as the keyboard, the mouse Live "paint", and so on), in short, almost all the code of a Windows Forms program. While this looks perfect, it creates a false sense of security-all anomalies are captured by central exception handling. The exception thrown by the worker thread is a good exception that is not captured by Application.ThreadException. (The code in the main method, including the form of a constructor, executes before the Windows information begins)

The. NET framework provides a lower-level event for global exception handling: Appdomain.unhandledexception, an event that is triggered by any unhandled exception on any thread of any type of program (with or without a user interface). Although it provides a good mechanism for exception handling, this does not mean that the program does not crash, and it does not mean that it can be canceled. NET Exception dialog box.

In a product program, explicitly using exception handling is necessary for all threads to enter the method, and you can use wrapper classes and helper classes to decompose work to accomplish tasks, such as using the BackgroundWorker class.

C # Multithreading practices-creating and starting to use

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.