"Go" writing high-quality Code 157 recommendations for improving C # programs--Recommendation 72: Using semaphores in thread synchronization

Source: Internet
Author: User
Tags semaphore

Recommendation 72: Use semaphores in thread synchronization

The so-called threading synchronization is that multiple threads perform a wait on an object (also understood to lock the object) until the object is unlocked. The types of objects in C # are categorized as reference types and value types. The CLR's wait on both types is not the same. We can simply understand that in the CLR, a value type cannot be locked, that is, the wait cannot be performed on a value type object. The wait mechanism on the reference type is divided into two categories: lock and Signal synchronization. The

Lock uses the keyword lock and type monitor. There is no real difference between the two, the former is actually the latter syntax sugar. This is the most common synchronization technology.

This recommendation mainly discusses signal synchronization. The types involved in the signal synchronization mechanism inherit from the abstract class WaitHandle, which have eventwaithandle (typed as AutoResetEvent, ManualResetEvent), Semaphore, and mutexes. See class Figure 6-3.

 
Figure 6-3 Class diagram of the synchronization feature class
EventWaitHandle (subclass AutoResetEvent, ManualResetEvent), Semaphore and mutexes inherit from WaitHandle, so the underlying principle is consistent, maintaining a system kernel handle. But we still need to simply distinguish between the three types of classes. The

EventWaitHandle maintains a Boolean type object (called a "block State") produced by the kernel, and if its value is false, the thread waiting on it is blocked. You can call the type's set method to set its value to true to unblock. The EventWaitHandle type has two subcategories of AutoResetEvent and ManualResetEvent, and their differences are not very big, and this recommendation will then explain how to use the semaphore correctly. The

Semaphore maintains a kernel-generated integer variable, and if its value is 0, the thread that waits on it blocks, and if its value is greater than 0, it is unblocked and the value is reduced by 1 for each thread being unblocked. The

EventWaitHandle and semaphore provide the thread synchronization functionality within a single application domain, unlike mutexes, which provide us with the ability to block and unblock threads across application domains. A simple example of

using a signaling mechanism to provide thread synchronization is as follows:

AutoResetEvent AutoResetEvent =NewAutoResetEvent (false); Private voidButtonstartathread_click (Objectsender, EventArgs e) {Thread Twork=NewThread (() ={Label1. Text="Thread Start ..."+Environment.NewLine; Label1. Text+="begin to deal with some practical work"+Environment.NewLine; //Omit work CodeLabel1. Text + ="I started to wait for another thread to give me a signal before I could go on."+Environment.NewLine;          Autoresetevent.waitone (); Label1. Text+="I went on to do some work, and then it ended! "; //Omit work Code    }); Twork.isbackground=true;  Twork.start (); }   Private voidButtonset_click (Objectsender, EventArgs e) {      //give a signal to the thread waiting on the AutoResetEventAutoResetEvent.Set (); } 


This is a simple WinForm form program, where one button is responsible for opening a new thread, and the other is responsible for sending a signal to the newly opened thread. Now explain in detail what happened.

New AutoResetEvent (false

This code creates a synchronization type Object AutoResetEvent, which sets its own default block state to False. This means that any thread that waits on it will be blocked. The so-called wait, is the application of the thread:

This shows that twork began to wait on the AutoResetEvent for any other place to give it a signal. The signal came, then Twork began to work, otherwise it would have been waiting (that is, blocking). Next look at this code in the main thread (in this case the UI thread, which is a "different thread" relative to thread twork):

The main thread sends a signal through the above code to the thread waiting on the AutoResetEvent twork context, setting the Twork block state to true. After receiving this signal, Twork began to work. This example is quite simple, but it has been fully explained how the signaling mechanism works. The difference between AutoResetEvent and ManualResetEvent is that the former will automatically set its block status to false when the signal is finished (that is, call the Set method), while the latter will need to be manually set. This distinction is illustrated by an example, as follows:

AutoResetEvent AutoResetEvent =NewAutoResetEvent (false); Private voidButtonstartathread_click (Objectsender, EventArgs e)      {StartThread1 ();  StartThread2 (); }   Private voidStartThread1 () {Thread TWork1=NewThread (() ={Label1. Text="thread 1 starts ..."+Environment.NewLine; Label1. Text+="begin to deal with some practical work"+Environment.NewLine; //Omit work CodeLabel1. Text + ="I started to wait for another thread to give me a signal before I could go on."+Environment.NewLine;          Autoresetevent.waitone (); Label1. Text+="I went on to do some work, and then it ended! "; //Omit work Code    }); Twork1.isbackground=true;  Twork1.start (); }   Private voidStartThread2 () {Thread TWork2=NewThread (() ={Label2. Text="thread 2 starts ..."+Environment.NewLine; Label2. Text+="begin to deal with some practical work"+Environment.NewLine; //Omit work CodeLabel2. Text + ="I started to wait for another thread to give me a signal before I could go on."+Environment.NewLine;          Autoresetevent.waitone (); Label2. Text+="I went on to do some work, and then it ended! "; //Omit work Code    }); Twork2.isbackground=true;  Twork2.start (); }   Private voidButtonset_click (Objectsender, EventArgs e) {      //give a signal to the thread waiting on the AutoResetEventAutoResetEvent.Set (); } 


The intent of this example is to block the new two worker threads TWork1 and TWORK2 until they receive a signal from the main thread to continue working. As a result of the program running, only one worker thread continues to work, while the other worker continues to remain blocked. I think maybe everyone has guessed the reason, that is, the AutoResetEvent sends the signal to automatically set its state back to false in the kernel, so another worker thread is equivalent to not receiving the main thread signal at all.

To fix this problem, you can use ManualResetEvent. You can change it to ManualResetEvent and try it.

Finally, a practical example that requires thread synchronization: Analog network communication. While the client is running, the server sends the heartbeat data to the client at every time. The actual work of the server and the client in the network is two different terminals, but in this example we have simplified it: The worker thread tclient the simulated client, the main thread (UI thread) to emulate the server side. The client detects if the server's heartbeat data is received every 3 seconds, and if there is no heartbeat data, the network connection is disconnected. The code looks like this:

AutoResetEvent AutoResetEvent =NewAutoResetEvent (false); Private voidButtonstartathread_click (Objectsender, EventArgs e) {Thread tClient=NewThread (() =        {               while(true)              {                  //wait 3 seconds, 3 seconds no signal, show disconnect//If there is a signal, the update is displayed                BOOLRe = Autoresetevent.waitone ( the); if(re) {Label1. Text=string. Format ("time: {0},{1}", DateTime.Now.ToString (),"Maintain Connection Status"); }                  Else{Label1. Text=string. Format ("time: {0},{1}", DateTime.Now.ToString (),"Disconnect, restart required");      }              }          }); Tclient.isbackground=true;  Tclient.start (); }   Private voidButtonset_click (Objectsender, EventArgs e) {      //simulate sending heartbeat dataAutoResetEvent.Set (); } 

Turn from: 157 recommendations for writing high-quality code to improve C # programs Minjia

"Go" writing high-quality Code 157 recommendations for improving C # programs--Recommendation 72: Using semaphores in thread synchronization

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.