C # multithreaded Programming brief

Source: Internet
Author: User

Reprint: http://www.knowsky.com/540518.html

NET defines the functionality of multithreading in the System.Threading namespace. Therefore, to use multi-threading, you must first declare a reference to this namespace (using System.Threading;).

A. Starting a thread
As the name implies, "Startup thread" is the meaning of creating and starting a thread, which is implemented as follows:
Thread thread1 = new Thread (new ThreadStart (Count));
Where Count is the function that will be executed by the new thread.
B. Kill a thread
"Kill a Thread" is to extermination a thread, in order not to waste effort, it is best to determine whether it is still alive (via the IsAlive property) before killing it, and then call the Abort method to kill the thread.
C. Suspending a thread
It means letting a running thread sleep for a while. such as thread. Sleep (1000); is to have the thread hibernate for 1 seconds.
D. Priority level
There's no need to explain this. The hreadpriority attribute in the thread class, which is used to set the priority, does not guarantee that the operating system will accept the priority level. The priority of a thread can be divided into 5 types: Normal, AboveNormal, BelowNormal, highest, Lowest. Examples of specific implementations are as follows:
Thread. priority = Threadpriority.highest;
E. Suspending a thread
The suspend method of the thread class is used to suspend the thread until the resume is called and the thread can continue execution. If the thread is already suspended, it will not work.
if (thread. ThreadState = threadstate.running)
{
Thread. Suspend ();
}
F. Recovering threads
Used to recover a suspended thread so that it continues to execute and 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 documentation.
Using System;
Using System.Threading;

//Simple threading Scenario:start A static method running
//on a second thread.
public class Threadexample {
//The ThreadProc method was called when the thread starts.
It Loops ten times, writing to the console and yielding 
//The rest of their time slice each 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);
}
}

public static void Main () {
Console.WriteLine ("Main Thread:start a second thread.");
The constructor for the Thread class requires a ThreadStart
Delegate that represents the method to being 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
Any processor time until the main thread yields. Uncomment
The thread.sleep that follows T.start () to see 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 ();
}
}

This code produces output 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 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.


The System.Threading namespace in Visul C # provides classes and interfaces that allow multithreaded programming, where threads are created in the following three ways: Thread, ThreadPool, Timer. Here is a brief description of how they are used.

First, Thread
This may be the most complex approach, but it provides a variety of flexible controls on threads. First you have to use its constructor to create a thread instance whose parameters are simple, with 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 precedence (enum Threadpriority:normal, Lowest, Highest, BelowNormal, AboveNormal).
The following example first generated two thread instances T1 and T2, then set their priority, then start two threads (two threads basically the same, except that they output different, T1 is "1", T2 for "2", according to their respective output character ratio can be roughly seen they occupy 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 <; i++)
{//Every run of a loop writes a "1"
Dosth ();
Console.Write ("1");
}
}
public static void Thread2 ()
{
for (int i = 0; i <; i++)
{//Every run of a loop writes a "2"
Dosth ();
Console.Write ("2");
}
}
public static void Dosth ()
{//used to simulate complex operations
for (int j = 0; J < 10000000; J + +)
{
int a=15;
A = A*a*a*a;
}
}
The result of the above program operation is:
11111111111111111111111111111111111111111121111111111111111111111111111111111111111112
11111111111111111111111111111111111111111121111111111111111111111111111111111111111112
11111111111111111111111111111111111111111121111111111111111111111111111111111111111112

From the above results we can see that the T1 thread consumes more CPU time than T2, this is because the T1 priority is higher than T2, if we set the T1 and T2 priority is normal, the results are as follows:
121211221212121212121212121212121212121212121212121212121212121212121
212121212121212121212121212121212121212121212121212121212121212121212
121212121212121212
As we can see from the example above, it is constructed similar to the Win32 worker thread, but it is much simpler to simply delegate the function that the thread is calling and then construct the thread instance as a parameter. When start () is called, the corresponding function is invoked, starting from the first line of the function.
We then combine the thread's ThreadState property to understand the thread's control. ThreadState is an enumeration type that reflects the state in which the thread is located.  When a thread instance has just been created, its threadstate is unstarted, and when this thread is called start (), its threadstate is Running; After this thread is started, if you want it to be paused (blocked), you can call the Thread.Sleep () method, which has two overloaded methods (sleep (int), sleep (Timespan)), except that it represents a different format for the amount of time, and when this function is called within a thread It indicates that this thread will block for a period of time (the time is determined by the number of milliseconds or timespan passed to Sleep, but if the parameter is 0 it means that the thread is suspended for other threads to execute, specifying Infinite to block threads indefinitely). At this point its threadstate will become waitsleepjoin, and it is also worth noting that the sleep () function is defined in order to static?! This also means that it cannot be combined with a thread instance, or it does not exist similar to T1. Call of Sleep (10)! It is true that the sleep () function can only be called by the thread that needs "sleep", and no other thread is allowed to call, just as when to sleep is a personal matter that cannot be determined by its people. But when a thread is in the WaitSleepJoin state and has to wake it up, you can use the Thread.Interrupt method, which will throw a threadinterruptedexception on the threads, let's look at an example first ( Notice how sleep is called):
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);
public static void Thread1 ()
{
Try
{//From the parameter can be seen will cause hibernation
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);
}
Operation Result: 1st interrupt
2nd Interrupt
(after 10s) T1 is end


From the example above we can see that the Thread.Interrupt method can wake the program from a blocking (waitsleepjoin) state into the corresponding interrupt handler, and then continue down (its threadstate also becomes running), The use of this function must be noted in the following points:
1. This method not only wakes up blocking caused by sleep, but also works for all methods (such as wait and join) that can cause threads to enter the WaitSleepJoin state. As shown in the example above, the method that causes the thread to block is put into the try block and the corresponding interrupt handler is placed inside the catch block.
2, for a thread call interrupt, if it is in the WaitSleepJoin state, then into 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, this is the reason why I used synchronization in order to ensure that the second call interrupt is called after the first interrupt, otherwise it might invalidate the second call (if it was called before the first interrupt). You can try to remove the synchronization, the result is probably: 1st interrupt
The previous example also used two other ways to get threads into the WaitSleepJoin state: Using synchronous objects and Thread.Join methods. The use of the Join method is simple, which means that the current thread that called this method is blocked until the other one (in this case, T1) terminates or passes a specified amount of time (if it also takes a time parameter), when any of the two conditions (if any) appear, It immediately ends the WaitSleepJoin state into the running state (which can be based on. The return value of the Join method determines what condition, true, is the thread terminates, and false is the time. A thread's pause is also available with the Thread.Suspend method, which calls the Suspend method when a thread is in the running state, and it goes into the suspendrequested state, but it is not immediately suspended until the thread reaches the security point before it can suspend the thread, at which point it will enter Susp Ended status. If the call to a thread that is already in suspended is not valid, you only need to call Thread.Resume to restore the run.
Finally we talk about thread destruction, and we can call the Abort method on the thread that needs to be destroyed, which throws ThreadAbortException on this thread. We can put some code inside the thread into the try block, and the corresponding processing code into the corresponding catch block, when the thread is executing the code inside the try block, if called Abort, it will jump into the corresponding catch block execution, after the execution of the catch fast code it will terminate ( If the resetabort in the catch block is different: It cancels the current abort request and continues down. So if you want to ensure that a thread terminates with the best join, as in the example above.

Second, ThreadPool
The thread pool (ThreadPool) is a relatively simple method that adapts to a number of short tasks that require multiple threads (such as some threads that are often in a blocking state), and its disadvantage is that the threads created cannot be controlled or prioritized. Since there is only one thread pool per process, and of course there is only one thread pool (snaplines) per application domain, you will find that the member functions of the ThreadPool class are static! When you first call ThreadPool.QueueUserWorkItem, ThreadPool.RegisterWaitForSingleObject, and so on, a thread pool instance is created. Here is a description of the two functions in the thread pool:
public static bool QueueUserWorkItem (//Successful call returns True
WaitCallback callback,//The delegate to be invoked by the thread to be created
Object state//arguments passed to the delegate
)//Its other overloaded function is similar, except that the delegate has no parameters
The purpose of this function is to queue threads to be created to the thread pool, create this thread when the thread pool's number of available threads is not zero (the line Cheng creates a limit of 25 threads), or it is queued to the thread pool until it has an available thread.
public static Registeredwaithandle RegisterWaitForSingleObject (
WaitHandle waitobject,//to register the WaitHandle
WaitOrTimerCallback callback,//thread Invocation of the delegate
Object state,//arguments passed to the delegate
The int timeout,//time-out, in milliseconds,
BOOL executeOnlyOnce file://whether to execute only once
);
public delegate void WaitOrTimerCallback (
The object state,//is also the argument passed to the delegate
BOOL Timedout//true is called because of a timeout, and vice versa because waitobject
);
The purpose of this function is to create a waiting thread that, once called, creates this thread, is in a "blocked" state until the parameter waitobject becomes signaled or the time timeout has been set, and it is worth noting that this "blocking" is very different from the WaitSleepJoin state of the thread: When a thread is in the WaitSleepJoin state, the CPU periodically wakes it up to poll the update status information and then enters the WaitSleepJoin state again, which is a resource-consuming switch. While the thread created with this function is different, the CPU does not switch to this thread before triggering it to run, it does not consume CPU time and does not waste thread switching time, but how does the CPU know when to run it? In fact, the thread pool generates a number of worker threads to monitor these trigger conditions, and when the condition is reached, the corresponding thread is started, and of course the worker threads themselves take time, but if you need to create more waiting threads, the advantage of using the thread pool becomes more pronounced. See the following example:
Static AutoResetEvent ev=new AutoResetEvent (false);
public static int Main (string[] args)
{ThreadPool.RegisterWaitForSingleObject (
Ev
New WaitOrTimerCallback (Waitthreadfunc),
4,
2000,
false//indicates that the timer is reset every time the wait operation is completed until the logoff 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 result of this operation is:
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 above results we can see that the thread ThreadFunc ran 1 times, while Waitthreadfunc ran 5 times. We can determine the reason for starting this thread from the bool T parameter in WaitOrTimerCallback: T is false, that is because of waitobject, otherwise it is due to a timeout. Alternatively, we can pass some parameters to the thread through object B.

3. Timer
It applies to methods that need to be called periodically, and it does not run in the thread that created the timer, it runs in a separate thread that is automatically assigned by the system. This is similar to the SetTimer method in Win32. It is constructed as:
Public Timer (
TimerCallback callback,//method to be called
The arguments passed to the callback by the object state,//
int duetime,//How long after you start calling callback
int period//the time interval at which this method is called
); If Duetime is 0, callback immediately executes its first call. If Duetime is Infinite, callback does not call its method. The timer is disabled, but you can re-enable it using the change method. If period is 0 or Infinite, and duetime is not Infinite, then callback calls its method one time. The periodic behavior of the timer is disabled, but you can re-enable it using the change method. If period is 0 (0) or Infinite, and duetime is not Infinite, then callback calls its method one time. The periodic behavior of the timer is disabled, but you can re-enable it using the change method.
If you want to change the period and duetime after the timer is created, we can change it by invoking the changing method of the timer:
public bool Change (
int Duetime,
int period
)///The two parameters that are obviously changed correspond to the two parameters in a timer
public static int Main (string[] args)
{
Console.WriteLine ("Period is 1000");
Timer tm=new Timer (new TimerCallback (Timercall), 3,1000,1000);
Thread.Sleep (2000);
Console.WriteLine ("Period is 500");
Tm. Change (0,800);
Thread.Sleep (3000);
return 0;
}
public static void Timercall (object B)
{
Console.WriteLine ("TimerCallback; B is {0} ", b);
}
The result of this operation is:
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 above brief introduction, we can see their respective use of the occasion: thread for those who need to have complex control of the thread; ThreadPool is adaptable to some shorter tasks that require multiple threads (such as some threads that are often blocked) The timer is suitable for those methods that need to be called periodically. As long as we understand the characteristics of their use, we can choose the right method.

C # multithreaded Programming brief

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.