Manualresetevent is a commonly used tool in C #. It can be used for inter-thread communication to implement a function similar to semaphores (I don't know if this is an appropriate description, but it may not be "similar ", and "yes" is implemented through semaphores, Because I recently learned this class and I have never known it before, haha. If you have any idea, please give it to me .).
First, let's take a look at the basic usage of manualresetevent:
1. Initialization: Public manualresetevent (bool initialstate );
The constructor of manualresetevent has a bool parameter. If it is true, it indicates that there is a signal. If it is false, it indicates that there is no signal. How can this be understood? Let's look at the waitone method in the three basic methods of manualresetevent.
2. waitone method: The waitone method has four kinds of overloading. Here I will only analyze its functions.
The waitone method, as its name implies, has a waiting function, that is, thread blocking. The blocking function is conditional. When there is no signal, it is blocked. When there is a signal, it will not be blocked, it is skipped directly when it is executed (logically, it should be quite understandable: when there is a signal to be processed, it needs to be processed immediately. If there is no signal, of course it is necessary to wait ). So, review to 1. When manualresetevent is initialized, The initialstate is false, and waitone will have blocking effect. Otherwise, there will be no blocking effect.
3. Set Method: Set the signal state of the manualresetevent object to a signal State. At this time, if waitone is blocking, the blocking will be terminated immediately and the task will continue to be executed. If this status remains unchanged, no blocking will occur when waitone is executed.
4. Reset method: set the signal status of the manualresetevent object to no-signal state. When waitone is executed the next time, blocking starts again.
In my personal understanding, manualresetevent has several methods to provide functions. Well, the Code is the king. Next, I will use an example of a production and consumption model to give you an axe!
Using system; using system. collections. generic; using system. LINQ; using system. text; using system. threading; namespace threadtest {class program {static void main (string [] ARGs) {New productandcosttester ();}} /// <summary> /// production consumption model /// </Summary> public class productandcosttester {/// <summary> /// line 1 thread /// </ summary> private thread _ producterthread1; /// <summary> /// Production Line 2 thread /// </Summary> private thread _ producterthread2; /// <summary> /// consumption line thread /// </Summary> private thread _ costerthread; /// <summary> /// product list /// </Summary> private list <int> _ goodlist; /// <summary> // manualresetevent instance // </Summary> private manualresetevent _ MRE; Public productandcosttester () {_ goodlist = new list <int> (); _ Mre = new manualresetevent (false); // when the initialization status of false is no signal, waitone blocking _ producterthread1 = new thread (product1); _ producterthread1.name = "productor1 "; _ producterthread1.start (); _ producterthread2 = new thread (product2); _ producterthread2.name = "productor2"; _ producterthread2.start (); _ costerthread = new thread (cost); _ costerthread. name = "costor"; _ costerthread. start () ;}/// <summary> /// Production Line 1 /// </Summary> void product1 () {While (true) {console. writeline (thread. currentthread. name + ":" + datetime. now. tostring ("HH: mm: SS"); For (INT I = 0; I <3; I ++) {_ goodlist. add (1);} _ MRE. set (); // indicates that there is a signal, notifying waitone not to block the thread. sleep (8000) ;}/// <summary> // Production Line 2 /// </Summary> void product2 () {While (true) {console. writeline (thread. currentthread. name + ":" + datetime. now. tostring ("HH: mm: SS"); For (INT I = 0; I <6; I ++) {_ goodlist. add (1);} _ MRE. set (); // indicates that there is a signal, notifying waitone not to block the thread. sleep (10000) ;}/// <summary> /// consumption line /// </Summary> void cost () {While (true) {If (_ goodlist. count> 0) {console. writeline ("cost" + _ goodlist. count + "at" + datetime. now. tostring ("HH: mm: SS"); _ goodlist. clear (); _ MRE. reset (); // reset to no signal, so that waitone can block again} else {console. writeline ("no cost at" + datetime. now. tostring ("HH: mm: SS"); _ MRE. waitone (); // if there is no consumable product, that is, there is no signal, it will block }}}}}
This code can be run directly and I will not use attachments anymore. Well, let me briefly explain what I want to express in this Code:
There are three threads, two production lines and one consumption line. The two production lines are carried out simultaneously, but the production speed may be inconsistent (here an 8 S/time, a 10 S/time ). Another consumption thread also runs at the same time as the production line. I want to achieve one goal: Whenever a product can be consumed, I will consume it immediately without any delay.
In the past, the simplest and most common idea was to let the consumption thread run sleep at a time, but this requires a short Loop Time and a fast enough cycle frequency. The frequency should be at least higher than any production thread, that is, the sleep time is smaller than the minimum sleep time in the production line.
If this is done, the code is logically free, but the efficiency is too low and may be in trouble. Suppose that the production frequency of the production thread is not fixed (unlike our fixed sleep for several seconds, this exists in the real situation ), sometimes the thread is only produced once an hour, sometimes it is produced once in 100 milliseconds (laugh, this is more extreme), then we need to set the sleep time of the consumption thread to at least 100 milliseconds. In this case, it is too wasteful when the production thread is one hour. Basically, the consumption thread is idling.
So, with this Code, each cycle of my consumption thread will check the number of products that have been produced. When there is a product available for consumption, I spent just one time and reminded me: "There are no consumable products, so I may have to wait for the next time!" (Call the reset method). If no product is found in the next loop, the system will wait (the waitone method is blocked ). At this time, the consumption thread will be completely stopped here and will not be idling every time. Is it more user-friendly? Haha.
Next, if any production thread produces a new product, it will notify the consumption thread: "Hey, dude, what you want is coming. Please wake up !" (Call the set method), so that the consumption thread will immediately continue to run (the waitone method will continue to run downward, and it will not be blocked before reset again ). Of course, the consumption thread will find a product available for consumption in the next cycle, and it will consume the product again, and remind: "There are no consumable products, you may need to wait next time!" (Call the reset method ). In this way, life is endless and cyclical.