Multithreaded programming in Visual C #

Source: Internet
Author: User
Tags bool join sleep terminates thread time interval valid win32
Visual| Programming | Multithreading C # is a common development tool for. NET platforms that can build all of them. NET application. All the threads in. NET run in the application domain (AppDomain), which may give you an idea of the WIN32 process, which is actually quite different. Application domains provide a secure and common processing unit that the common language runtime can use to isolate applications. Notice in the. NET is an application domain, not a process, there are several application domains that can exist in a single process, and threads can span the scope of an application domain, and methods in one thread can invoke the methods of another thread, so that there is no additional overhead in inter-process calls or inter-process switching. It can be said that an application domain is a logical process within a physical process (also known as a process in Win32).
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. Let me give a brief description of how they are used.
1. 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, its parameters are simpler, and there is only one ThreadStart delegate:
[C #]
Public Thread (ThreadStart start);
Then invoke start () to start it, and of course you can use its Priority property to set or get its run priority (enum Threadpriority:normal, Lowest, highest, BelowNormal, AboveNormal). See the following example: It 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" on each loop
Dosth ();
Console.Write ("1");
}
}
public static void Thread2 ()
{
for (int i = 0; i < 1000; i++)
{//write a "2" on each loop
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 results of the above programs are:

11111111111111111111111111111111111111111121111111111111111111111111111111111111111112

11111111111111111111111111111111111111111121111111111111111111111111111111111111111112

11111111111111111111111111111111111111111121111111111111111111111111111111111111111112

As we can see from the above results, the T1 thread takes up more CPU time than T2, because the T1 priority is higher than the T2, and if we set the T1 and T2 priorities to normal, what is the result? Do they consume the same amount of CPU time? Yes, as you would expect, see the figure below:

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 threading 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 causes the threadinterruptedexception to be on the thread, Let's take a look at one 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);
public static void Thread1 ()
{
Try
{//From the parameters 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");
}//suspend 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 the program from a blocking (waitsleepjoin) state into the corresponding interrupt handler, and then continue to execute (its threadstate also become running), the use of this function must pay attention to the following points:
1. This method not only wakes up the blocking caused by sleep, but is also valid for all methods (such as wait and join) that can cause threads to enter the WaitSleepJoin state. 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. For a thread call interrupt, if it is in the WaitSleepJoin state, then enter the corresponding interrupt handler execution, if it is not in the WaitSleepJoin state, then it will be immediately interrupted when it enters this state. 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 place the corresponding processing code inside the appropriate catch block, and when the thread is executing the code in the try block, as called Abort, it jumps into the appropriate catch block to execute, It terminates after execution of the code within the catch fast (ResetAbort is different if the catch block is executed: 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.
2. 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. I'll give you a description of the two functions in the thread pool:
[C #]
public static bool QueueUserWorkItem (//Call Success returns TRUE)
WaitCallback callback,//The delegate to be created by the thread call
Object state//arguments passed to the delegate
//It's another overloaded function similar, just the delegate without parameters
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.
[C #]
public static Registeredwaithandle RegisterWaitForSingleObject (
WaitHandle waitobject,//to be registered WaitHandle
WaitOrTimerCallback a delegate called by a callback,//thread
Object state,//The arguments passed to the delegate
int timeout,//timeout, in milliseconds,
BOOL executeOnlyOnce file://Yes/no only once
);
public delegate void WaitOrTimerCallback (
Object state,//is also the argument passed to the delegate
BOOL Timedout//true indicates that due to a timeout call, the vice versa because 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,
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 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:
[C #]
Public Timer (
TimerCallback callback,//The method required for the call
Object state,//The arguments passed to callback
How long after the int duetime,//starts calling callback
int period//The time interval when this method is called
//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:
[C #]
public bool Change (
int Duetime,
int period
)//Obviously the changed two parameters correspond to two parameters in the timer
See the following example: 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 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.




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.