Brief Introduction to C # Multithreading Simple example explanation _c# tutorial

Source: Internet
Author: User
Tags sleep terminates thread class win32

. NET defines the function of multithreading in the System.Threading namespace. Therefore, to use multiple threads, you must first declare a reference to this namespace (using System.Threading;).

A. Start a thread

As the name suggests, "Start a thread" is to create a new and start a thread meaning, the following code can be implemented:

Thread thread1 = new Thread (new ThreadStart (Count));

The Count is the function that will be executed by the new thread.

B. Killing threads

"Kill a Thread" is to destroy the first thread, in order not to waste effort, before killing one of the threads, it is best to determine whether it is still alive (through the IsAlive property), and then can call the Abort method to kill the thread.

C. Pausing a thread

It means to keep a running thread dormant for a period of time. such as thread. Sleep (1000); is to keep the thread dormant for 1 seconds.

D. Priority

There's no need to explain this. The Hreadpriority property in the thread class, which is used to set precedence, but does not guarantee that the operating system will accept the priority level. The priority of a thread can be divided into 5 kinds: Normal, AboveNormal, BelowNormal, highest, Lowest. The specific implementation examples are as follows:

Thread. Priority = Threadpriority.highest;

E. Suspending Threads

The suspend method of the thread class is used to suspend the thread until the resume is invoked before the thread can continue execution. If the thread is already suspended, it will not work.

if (thread. ThreadState = threadstate.running) 
{
thread. Suspend ();
}

F. Recovery threads

Used to recover a thread that has been suspended so that it continues to execute, and it will not work if the thread is not suspended.

if (thread. ThreadState = threadstate.suspended) 
{
thread. Resume ();
}

An example is listed below to illustrate the simple threading functionality. This example comes from the Help document.

Using System;

Using System.Threading;
Simple threading Scenario:start A static method running//on a second thread. The public class Threadexample {//The ThreadProc be called when the thread starts.//It loops ten times, writing to
The console and yielding//the rest of the slice per time, and then ends. public static void ThreadProc () {for (int i = 0; i < i++) {Console.WriteLine ("ThreadProc: {0}", i);//Yield the
Rest of the time slice.
Thread.Sleep (0); The public static void Main () {Console.WriteLine ("Main Thread:start a second thread.");//The constructor for the thre Ad class requires a ThreadStart//delegate that represents the "method to" executed on the//thread.
C # simplifies the creation of this delegate.
Thread t = new Thread (new ThreadStart (ThreadProc)); Start ThreadProc. On a uniprocessor, the thread does not get//No processor time until the main thread yields. Uncomment//The thread.sleep that follows T.start () to the DIFFerence.
T.start ();

Thread.Sleep (0);
for (int i = 0; i < 4; i++) {Console.WriteLine ("Main thread:do some work.");
Thread.Sleep (0);
} Console.WriteLine ("Main Thread:call Join (), to wait until ThreadProc ends.");
T.join (); Console.WriteLine ("Main Thread:ThreadProc.Join has returned.
Press Enter to end program. ");
Console.ReadLine ();

 }
}

The output generated by this code is similar to the following:

Main Thread:start a second thread.
Main thread:do some work.
threadproc:0
Main thread:do some work.
Threadproc:1
Main thread:do some work.
Threadproc:2
Main thread:do some work.
Threadproc:3
Main Thread:call Join () to the wait until ThreadProc ends.
Threadproc:4
threadproc:5
threadproc:6
threadproc:7
threadproc:8
threadproc:9 Main Thread:ThreadProc.Join has returned. Press Enter to end program.

In Visul C # system.threading namespaces provide classes and interfaces that allow multithreaded programming, in which threads are created in the following three ways: Thread, ThreadPool, Timer. Here is a brief description of how they are used.

First, Thread

This is perhaps the most complex method, but it provides a variety of flexible controls over threads. First you have to use its constructor to create a thread instance with simple arguments, only one ThreadStart delegate: Public Thread (ThreadStart start), and then call Start () to start it, Of course you can use its Priority property to set or get its run priority (enum Threadpriority:normal, Lowest, Highest, BelowNormal, AboveNormal).

The following example first generates two thread instances T1 and T2, then set their priority, then start the two threads (two threads are basically the same, but they output is not the same, T1 is "1", T2 is "2", according to their respective number of output characters can be roughly see their CPU time ratio, This also reflects their respective priorities).

static void Main (string[] args)
{
 thread t1 = new Thread (new ThreadStart (THREAD1));
 Thread t2 = new Thread (new ThreadStart (Thread2));

 T1. Priority = Threadpriority.belownormal;
 T2. Priority = threadpriority.lowest;
   T1. Start ();
  T2. Start ();
 }
public static void Thread1 ()
{for 
 (int i = 1; i < 1000; i++) 
 {//write a "1"
  dosth () for Each loop;
 Console.Write ("1");
 }
public static void Thread2 ()
{for 
 (int i = 0; i < 1000; i++) 
 {//write a "2"
 dosth () for Each loop;
 Console.Write ("2");
 }
The public static void Dosth ()
{///is used to simulate complex operations for
 (int j = 0; J < 10000000; J + +) 
 { 
 int a=15;
 A = A*a*a*a;
 }
}

The results of the above programs are:

11111111111111111111111111111111111111111121111111111111111111111111111111111111111112
11111111111111111111111111111111111111111121111111111111111111111111111111111111111112
11111111111111111111111111111111111111111121111111111111111111111111111111111111111112

From the above results, we can see that the T1 thread consumes more CPU time than T2, because the T1 priority is higher than the T2, and if we set the priority of T1 and T2 to normal, the result is as follows:

121211221212121212121212121212121212121212121212121212121212121212121
212121212121212121212121212121212121212121212121212121212121212121212
121212121212121212

As we can see from the example above, it is constructed like a Win32 worker thread, but it is much simpler to simply take the function that the thread is calling as a delegate, and then construct the thread instance with the delegate as a parameter. When start () is invoked, the corresponding function is called, starting with the first line of the function.

Next we combine the thread's ThreadState properties to understand the thread's control. ThreadState is an enumeration type that reflects the state of the thread.  When a thread instance is just created, its threadstate is unstarted, and its threadstate is Running after it is invoked to start (); After this thread has started, if you want it to pause (block), you can call the Thread.Sleep () method, which has two overloaded methods (sleep (int), Timespan), but only a different format for the amount of time, when this function is called within a thread. It means that this thread will block for some time (the time is determined by the number of milliseconds passed to sleep, or timespan, but if the argument is 0 to suspend this thread so that other threads can execute, specifying Infinite to block the thread indefinitely), At this point its threadstate will become waitsleepjoin, and it is worth noting that the sleep () function is defined to static?! This also means that it cannot be combined with a thread instance, nor does it exist similar to T1. Sleep (10) call! As such, the sleep () function can only be invoked by the thread that needs "sleep" and not by other threads, just as it is a personal matter that cannot be decided by someone else. But when a thread is in a waitsleepjoin state and has to wake it up, you can use the Thread.Interrupt method, which throws the threadinterruptedexception on the thread, and let's take a look at an example ( Note the call method for sleep):

static void Main (string[] args)
{ 
 thread t1 = new Thread (new ThreadStart (THREAD1));
 T1. Start ();
  T1. Interrupt ();
  E.waitone ();
  T1. Interrupt ();
   T1. Join ();
   Console.WriteLine ("T1 is End");
}
static AutoResetEvent E = new AutoResetEvent (false);
The public static void Thread1 ()
{ 
 try
 {//) can be seen from the parameters that will cause the Hibernate
 thread.sleep (timeout.infinite); 
 }
 catch (System.Threading.ThreadInterruptedException e)
 {//Interrupt handler
 Console.WriteLine ("1st Interrupt");
 }
  E.set ();
 Try
 {//Hibernate
 Thread.Sleep (timeout.infinite); 
 }
 catch (System.Threading.ThreadInterruptedException e)
 {
  Console.WriteLine ("2nd Interrupt");
 } Pause for 10 seconds
   Thread.Sleep (10000); 
  }

The results of the operation are:

1st Interrupt
2nd Interrupt
(10s) T1 is end

From the example above we can see that the Thread.Interrupt method can wake a program from a blocking (waitsleepjoin) state into the corresponding interrupt handler, and then continue to execute (its threadstate also becomes running), The following points must be noted in the use of this function:

1, this method can not only wake up the blocking caused by sleep, but also all the methods that can cause the thread to enter the WaitSleepJoin state (such as wait and join) are valid. As shown in the example above, use the method that causes the thread to block into the try block and place the appropriate interrupt handler inside the catch block.

2, to a thread call interrupt, such as it is in the WaitSleepJoin state, then enter the corresponding interrupt handler execution, if it is not in the WaitSleepJoin state, then it later entered this state, will be immediately interrupted. If you call interrupt several times before the interrupt, only the first call is valid, which is why I used synchronization to make sure that the second call interrupt is invoked after the first interrupt, otherwise it might cause the second call to be invalid (if it was invoked before the first interrupt). You can try to remove the sync, the result is likely to be: 1st interrupt

The previous example also uses two other methods for threading the thread into the WaitSleepJoin state: Using the synchronization object and the Thread.Join method. The Join method is relatively simple to use, which means that the current thread that calls this method is blocked until another thread (in this case, T1) terminates or has elapsed a specified amount of time (if it also has a time measure parameter), when two conditions (if any) appear, It immediately ends the WaitSleepJoin state entering the running state (which can be based on. The return value of the Join method determines what condition, true, the thread terminates, and false is the time. A thread's pause can also be a Thread.Suspend method that calls the Suspend method on a thread when it is in the running state, and it goes into the suspendrequested state, but it is not immediately suspended until the thread has reached a safe point before it can suspend the thread, and it will enter the Susp Ended state. It is not valid to invoke a thread that is already suspended, and to recover it is to simply call Thread.Resume.

In the end we talk about thread destruction, we can call the Abort method on the thread that needs to be destroyed, and it throws ThreadAbortException on this thread. We can put some code inside the thread into a try block, and put the corresponding processing code into the appropriate catch block, when the thread is executing the code in the try block, such as called Abort, it will jump into the appropriate catch block execution, after the execution of the catch-fast code, it will terminate ( If ResetAbort is executed within the catch block, it is different: it cancels the current abort request and continues down execution. So if you want to make sure that a thread terminates the best join, as in the example above.

Second, ThreadPool

A thread pool (ThreadPool) is a relatively simple method that is adapted to a number of threads that require shorter tasks, such as those that are often blocked, and whose disadvantage is that the threads that are created cannot be controlled or prioritized. Since there is only one thread pool per process, and of course each application domain has only one thread pool (snaplines), you will find that the member functions of the ThreadPool class are all static! The thread pool instance is created when you first call ThreadPool.QueueUserWorkItem, ThreadPool.RegisterWaitForSingleObject, and so on. Here is a description of the two functions in the thread pool:

public static bool QueueUserWorkItem (///Call Success returns True
WaitCallback callback,//The delegate
  object state//That is called by the thread to be created. The argument passed to the delegate
)//It's another overloaded function similar, except that the delegate takes no arguments.

The purpose of this function is to queue the threads to be created to the thread pool, this thread is created when the thread pool does not have the number of available threads (the line Cheng the limit of the number of threads created, and the body value is 25), otherwise it is queued to the thread pool until it has a thread available.

public static Registeredwaithandle RegisterWaitForSingleObject (
 WaitHandle waitobject,//to be registered WaitHandle
 WaitOrTimerCallback callback,//The delegate object that the thread invokes is
 passed to the delegate's argument
 int timeout,//timeout, in milliseconds,
 bool executeOnlyOnce file://is only performed once
); 
The public delegate void WaitOrTimerCallback (
 object state,//is also passed to the delegate's argument
 bool Timedout//true indicates that the timeout call Conversely, because of the waitobject
);

The role of this function is to create a waiting thread that, once called, creates this thread, is in a "blocking" state when the parameter waitobject becomes signaled or the time set timeout to be blocked, and it is worth noting that this "blocking" And the WaitSleepJoin state of thread is very different: when a thread is in the WaitSleepJoin state, the CPU periodically wakes it up to poll the update status information, and then into the WaitSleepJoin state again, the thread switching is very resource-heavy While the thread created with this function is different, the CPU does not switch to this thread until it is fired, it does not consume CPU time, and it does not waste thread switching time, but how does the CPU know when to run it? The thread pool actually generates some worker threads to monitor these triggering conditions, and the corresponding threads are started when the conditions are reached, although the worker threads themselves take time, but the advantage of using the thread pool becomes more apparent if you need to create more waiting threads. See the following example:

Static AutoResetEvent ev=new AutoResetEvent (false);
public static int Main (string[] args)
{threadpool.registerwaitforsingleobject (
  ev,
  new WaitOrTimerCallback (Waitthreadfunc),
  4,
  false//, which means that the
  timer is reset every time the wait operation is completed, until the logout Waits
  );
ThreadPool.QueueUserWorkItem (New WaitCallback (ThreadFunc), 8);
Thread.Sleep (10000);
 return 0;
}
 public static void ThreadFunc (object B)
{Console.WriteLine (' The object is {0} ', b);
for (int i=0;i<2;i++)
{thread.sleep (1000);
 Ev. Set ();
}
}
public static void Waitthreadfunc (Object B,bool t)
{Console.WriteLine ("The object is {0},t is {1}", b,t);
 }

The results of the operation are:

The object is 8
The object is 4,t is False
The object is 4,t is False
The object is 4,t is True
The object is 4,t is True
The object is 4,t is True

From the results above we can see that the thread ThreadFunc ran 1 times, while Waitthreadfunc ran 5 times. We can judge the reason for starting this thread from the bool T parameter in WaitOrTimerCallback: "T is false, it means because of waitobject, otherwise it is due to timeout." In addition, we can pass some parameters to the thread via object B.

3, Timer

This applies to methods that need to be called periodically, not running in a thread that creates a timer, which runs in a separate thread that is automatically allocated by the system. This is similar to the SetTimer method in Win32. It is constructed as follows:

Public Timer (
 TimerCallback callback,//The required method
 object state,//passed to the callback parameter
 int duetime,// How long after you start calling callback
 int period//The time interval to call this method

If Duetime is 0, callback immediately executes its first call. If Duetime is Infinite, then callback does not call its method. The timer is disabled, but you can use the change method to re-enable it. If period is 0 or Infinite, and duetime is not Infinite, the method that invokes it is callback once. The timer's periodic behavior is disabled, but you can use the change method to re-enable it. If period is 0 (0) or Infinite, and duetime is not Infinite, the method that invokes it is callback once. The timer's periodic behavior is disabled, but you can use the change method to re-enable it.

If you want to change the period and duetime of a timer after you create it, we can change it by calling the timer's changing method:

public bool Change (
 int duetime,
 int period
);/Obviously the two parameters that are changed correspond to the two parameters in the timer public
static int Main (string [] args
{ 
Console.WriteLine ("Period is 1000");
Timer tm=new Timer (new TimerCallback (Timercall), 3,1000,1000);
Thread.Sleep ();
Console.WriteLine ("Period is)";
Tm. Change (0,800);
Thread.Sleep (3000);
return 0;
 }
public static void Timercall (object B)
{ 
Console.WriteLine ("TimerCallback; B is {0} ", b);
}

The results of the operation are:

Period is 1000
Timercallback;b is 3
Timercallback;b is 3
Period is 500
Timercallback;b is 3
Timercallback;b is 3
Timercallback;b is 3
Timercallback;b is 3

Summarize

From the simple introduction above, we can see where they are used: thread is suitable for those situations where the thread is subject to complex control, and the ThreadPool is adapted to some tasks that require multiple threads and are shorter (for example, some threads that are often blocked) ; The timer applies to methods that need to be called periodically. As long as we understand the characteristics of their use, we can choose the right way.

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

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.