. Net brief introduction to component programming (manual synchronization)

Source: Internet
Author: User

In the previous articleArticleIn ". Net introduction to component programming (context and synchronization domain)", we learned some concepts about context and synchronization domain, which can be used for automatic synchronization.

Today, we mainly learn how to manually execute synchronization and block it at a smaller granularity to Maximize throughput.[Wang qingpei has all rights reserved. For more information, please sign it.]

We know that a thread is the running entity of a process, a process is the resource allocation unit, and a thread is the execution unit. As the book says, the thread isProgramWhen we allocate a thread, we need to determine the thread's execution path, that isCodeThe method of the entry point pointed to by the threadstart delegate in.

Once we start the thread manually, the current context thread will be switched by the system immediately. you can accurately obtain the currently executed thread instance in the static property of currentthread, and then perform a series of settings, waiting, and termination.[Wang qingpei has all rights reserved. For more information, please sign it.]

So how does a thread implement synchronization (mutex)? In our normal code, there is no real code about thread synchronization, therefore, there is no implementation code in the thread execution path that can block the thread. To implement thread blocking, you must write something in the thread's execution path so that all threads can enter this code (that is, critical resources ), determine whether to allow execution by judging something.

Figure 1:

In the threadstartenterpoint method, if no synchronization code is available, any thread can go in and execute it, resulting in messy data. When data is in the memory, the code of the thread can only be executed by the CPU at the same time, but the thread is in competition. When thread 1 has not been fully executed, thread 2 executes this piece of data, causing data to be not synchronized.

So we need to re-thread 1, before the execution is complete, other threads are not allowed to use this memory object. When thread 1 is used up, the occupied resources are immediately released to allow other threads to compete.

Use monitor for synchronization

Monitor is a synchronization object that can lock an object at a certain time point. See the Code:

[Methodimpl (methodimploptions. synchronized)] public void showmessage () {for (INT I = 0; I <10; I ++) {if (I = 5) Monitor. wait (this); // after the second thread is used up, I will continue to execute it. Place the current thread in the waiting queue thread currentthread = thread. currentthread; console. writeline (currentthread. name + "|" + currentthread. managedthreadid + "|" + I. tostring () ;}} [methodimpl (methodimploptions. synchronized)] public void plusethread () {for (INT I = 0; I <10; I ++) {thread currentthread = thread. currentthread; console. writeline (currentthread. name + "|" + currentthread. managedthreadid + "|" + I. tostring ();} monitor. pulse (this); // put the threads in the waiting queue into the locked queue, that is, monitor. enter ();}

 

This is two methods in a class. In the method header, I used the methodimpl method feature for identification. In fact, the purpose of this feature is to add the synchronization method at the entrance and end of the method, that is, monitor. enter and monitor. exit. Generally, we are used to locking objects with lock. In fact, lock is also a variation of monitor. I will not write it here. Let's get familiar with the unfamiliar usage.

 
Myclass1 myclass = new myclass1 (); threadstart startdeleted = new threadstart (myclass. showmessage); thread = new thread (startdeleted); thread. name = "thread 1"; threadstart stra = new threadstart (myclass. plusethread); thread thread2 = new thread (stra); thread2.name = "thread 2"; thread. start (); thread2.start (); thread2.join (); console. writeline ("thread 2 has been released"); thread. join (); console. writeline ("thread 1 has been released"); console. writeline (thread. currentthread. managedthreadid); console. readline ();

 

In the called code, this probably means that we can start two threads at the same time, and the entry points are the two methods above, in plusethread, it is used to release showmessage thread 1 from the waiting queue and continue execution.[Wang qingpei has all rights reserved. For more information, please sign it.]

In showmessage, I use the monitor. Wait method to wait. When this method is called, I will use the locked object to let other threads enter the execution. When monitor. pluse is executed, thread 1 continues.

The static monitor object is the path that every thread will execute. We control the monitor for thread synchronization. When we call wait, we will wait until the current object pluse continues to execute.

Figure 2:

Use waithandle for synchronization

 

In the above process, we use monitor for synchronization. During synchronization, we need to control the wait time well. We can also use monitor to set the wait time-out through wait. Maybe it is encapsulated as a Windows wait handle.

Waithandle is used for synchronization. waithandle is an abstract class and has many subclasses, such as mutex, manualresetevent, and autoresetevent event object. Next we will look at how to use these objects to synchronize threads.

Mutext mutex

Public void print () {mutex = new mutex (false, "myclass"); // mutex. waitone (); For (INT I = 0; I <10; I ++) {console. writeline (I. tostring () + thread. currentthread. name);} mutex. releasemutex ();}

 

In the method, we apply for a mutex object. The mutex object is global, that is, only one mutex with the same name can exist on a machine. mutex can be used to synchronize threads or processes.

We use waitone in the print method to get the handle. If there is already a thread "first-in-first-out", it will block and return false.

Call releasemutex to release the currently occupied mutex handle.

Myclass1 myclass = new myclass1 (); thread = new thread (New threadstart (myclass. print); thread. name = "thread 1"; thread thread2 = new thread (New threadstart (myclass. print); thread2.name = "thread 2"; thread. start (); thread2.start (); thread2.join (); thread. join (); console. writeline (thread. currentthread. managedthreadid );

 

Figure 3:

Use manualresetevent (manual event) for synchronization

Let's look at the code. manualresetevent may be used by everyone.

Public class eventwaithandlerdemo {manualresetevent resetevent = new manualresetevent (false); Public eventwaithandlerdemo () {thread = new thread (New threadstart (this. dowork); thread. start ();} private void dowork () {int COUNT = 0; while (true) {resetevent. waitone (); console. writeline (count ++) ;}} public void gothread () {resetevent. set (); console. writeline ("thread startup");} public void stopthread () {resetevent. reset (); console. writeline ("thread paused");} public void close () {resetevent. close (); console. writeline ("thread termination ");}}

 

This type of wait handle object is completely manually controlled, so we need to remember set when we want to use it, and reset when we want to suspend it, and close when we don't need it.

Eventwaithandlerdemo demo = new eventwaithandlerdemo (); demo. gothread (); thread. sleep (1000); demo. stopthread (); thread. sleep (1000); demo. close (); console. writeline ("program ended ");

 

Figure 4:

Use autoresetevent for synchronization

From the name, we can see that this event is an automatic reset event and does not need to perform the set \ reset operation as above.

Public class autoreseteventdemo {autoresetevent autoevent = new autoresetevent (true); Public autoreseteventdemo () {} public void print () {autoevent. waitone (); // autoevent. reset (); in manual events, you need to manually switch the status int I = 0; while (true) {if (I = 10) {console. writeline (thread. currentthread. name + "End of thread"); autoevent. set (); break;} console. writeline (thread. currentthread. managedthreadid + "|" + I ++ );}}}

 

In the above Code, we get the waiting handle through waitone. After we get the wait handle, the event object will be automatically reset to the signal that has been sent, and other threads cannot get the waiting handle. Only other threads can obtain this information after we set it. What is saved here is that the thread enters the execution path.

Manualresetevent can be used only after Manual set. Once the signal is marked as unsent after set, all threads can execute code, unless manual reset can be blocked.

Console. writeline (thread. currentthread. managedthreadid); autoreseteventdemo autodemo = new autoreseteventdemo (); thread thread1 = new thread (New threadstart (autodemo. print); thread1.name = "thread 1"; thread thread2 = new thread (New threadstart (autodemo. print); thread2.name = "thread 2"; thread1.start (); thread2.start (); thread1.join (); thread2.join (); console. writeline (thread. currentthread. managedthreadid); console. read ();

 

Figure 5:

[Wang qingpei has all rights reserved. For more information, please sign it.]

 

 

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.