autoresetevent https://www.e-learn.cn/tag/autoresetevent zh-hans What is the difference between ManualResetEvent and AutoResetEvent in .NET? https://www.e-learn.cn/topic/3155700 <span>What is the difference between ManualResetEvent and AutoResetEvent in .NET?</span> <span><span lang="" about="/user/202" typeof="schema:Person" property="schema:name" datatype="">醉酒当歌</span></span> <span>2020-01-08 17:22:35</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>I have read the documentation on this and I think I understand. An AutoResetEvent resets when the code passes through <code>event.WaitOne()</code>, but a ManualResetEvent does not.</p> <p>Is this correct?</p> <br /><h3>回答1:</h3><br /><p>Yes. It's like the difference between a tollbooth and a door. The <code>ManualResetEvent</code> is the door, which needs to be closed (reset) manually. The <code>AutoResetEvent</code> is a tollbooth, allowing one car to go by and automatically closing before the next one can get through.</p> <br /><br /><br /><h3>回答2:</h3><br /><p>Just imagine that the <code>AutoResetEvent</code> executes <code>WaitOne()</code> and <code>Reset()</code> as a single atomic operation.</p> <br /><br /><br /><h3>回答3:</h3><br /><p>The short answer is yes. The most important difference is that an AutoResetEvent will only allow one single waiting thread to continue. A ManualResetEvent on the other hand will keep allowing threads, several at the same time even, to continue until you tell it to stop (Reset it).</p> <br /><br /><br /><h3>回答4:</h3><br /><blockquote> <p>Taken from C# 3.0 Nutshell book, by Joseph Albahari</p> </blockquote> <p>Threading in C# - Free E-Book</p> <p>A ManualResetEvent is a variation on AutoResetEvent. It differs in that it doesn't automatically reset after a thread is let through on a WaitOne call, and so functions like a gate: calling Set opens the gate, allowing any number of threads that WaitOne at the gate through; calling Reset closes the gate, causing, potentially, a queue of waiters to accumulate until its next opened.</p> <p>One could simulate this functionality with a boolean "gateOpen" field (declared with the volatile keyword) in combination with "spin-sleeping" – repeatedly checking the flag, and then sleeping for a short period of time.</p> <p>ManualResetEvents are sometimes used to signal that a particular operation is complete, or that a thread's completed initialization and is ready to perform work.</p> <br /><br /><br /><h3>回答5:</h3><br /><p>I created simple examples to clarify understanding of <code>ManualResetEvent</code> vs <code>AutoResetEvent</code>.</p> <p><code>AutoResetEvent</code>: lets assume you have 3 workers thread. If any of those threads will call <code>WaitOne()</code> all other 2 threads will stop execution and wait for signal. I am assuming they are using <code>WaitOne()</code>. It is like; if I do not work, nobody works. In first example you can see that</p> <pre><code>autoReset.Set(); Thread.Sleep(1000); autoReset.Set(); </code></pre> <p>When you call <code>Set()</code> all threads will work and wait for signal. After 1 second I am sending second signal and they execute and wait (<code>WaitOne()</code>). Think about these guys are soccer team players and if one player says I will wait until manager calls me, and others will wait until manager tells them to continue (<code>Set()</code>)</p> <pre><code>public class AutoResetEventSample { private AutoResetEvent autoReset = new AutoResetEvent(false); public void RunAll() { new Thread(Worker1).Start(); new Thread(Worker2).Start(); new Thread(Worker3).Start(); autoReset.Set(); Thread.Sleep(1000); autoReset.Set(); Console.WriteLine("Main thread reached to end."); } public void Worker1() { Console.WriteLine("Entered in worker 1"); for (int i = 0; i &lt; 5; i++) { Console.WriteLine("Worker1 is running {0}", i); Thread.Sleep(2000); autoReset.WaitOne(); } } public void Worker2() { Console.WriteLine("Entered in worker 2"); for (int i = 0; i &lt; 5; i++) { Console.WriteLine("Worker2 is running {0}", i); Thread.Sleep(2000); autoReset.WaitOne(); } } public void Worker3() { Console.WriteLine("Entered in worker 3"); for (int i = 0; i &lt; 5; i++) { Console.WriteLine("Worker3 is running {0}", i); Thread.Sleep(2000); autoReset.WaitOne(); } } } </code></pre> <p>In this example you can clearly see that when you first hit <code>Set()</code> it will let all threads go, then after 1 second it signals all threads to wait! As soon as you set them again regardless they are calling <code>WaitOne()</code> inside, they will keep running because you have to manually call <code>Reset()</code> to stop them all. </p> <pre><code>manualReset.Set(); Thread.Sleep(1000); manualReset.Reset(); Console.WriteLine("Press to release all threads."); Console.ReadLine(); manualReset.Set(); </code></pre> <p>It is more about Referee/Players relationship there regardless of any of the player is injured and wait for playing others will continue to work. If Referee says wait (<code>Reset()</code>) then all players will wait until next signal.</p> <pre><code>public class ManualResetEventSample { private ManualResetEvent manualReset = new ManualResetEvent(false); public void RunAll() { new Thread(Worker1).Start(); new Thread(Worker2).Start(); new Thread(Worker3).Start(); manualReset.Set(); Thread.Sleep(1000); manualReset.Reset(); Console.WriteLine("Press to release all threads."); Console.ReadLine(); manualReset.Set(); Console.WriteLine("Main thread reached to end."); } public void Worker1() { Console.WriteLine("Entered in worker 1"); for (int i = 0; i &lt; 5; i++) { Console.WriteLine("Worker1 is running {0}", i); Thread.Sleep(2000); manualReset.WaitOne(); } } public void Worker2() { Console.WriteLine("Entered in worker 2"); for (int i = 0; i &lt; 5; i++) { Console.WriteLine("Worker2 is running {0}", i); Thread.Sleep(2000); manualReset.WaitOne(); } } public void Worker3() { Console.WriteLine("Entered in worker 3"); for (int i = 0; i &lt; 5; i++) { Console.WriteLine("Worker3 is running {0}", i); Thread.Sleep(2000); manualReset.WaitOne(); } } } </code></pre> <br /><br /><br /><h3>回答6:</h3><br /><p><code>autoResetEvent.WaitOne()</code> </p> <p>is similar to</p> <pre><code>try { manualResetEvent.WaitOne(); } finally { manualResetEvent.Reset(); } </code></pre> <p>as an atomic operation</p> <br /><br /><br /><h3>回答7:</h3><br /><p>OK, normally it does not a good practice to add 2 answers in same thread, but I did not want to edit/delete my previous answer, since it can help on another manner.</p> <p>Now, I created, much more comprehensive, and easy to understand, run-to-learn console app snippet below.</p> <p>Just run the examples on two different consoles, and observe behaviour. You will get much more clear idea there what is happening behind the scenes.</p> <p><strong>Manual Reset Event</strong></p> <pre><code>using System; using System.Threading; namespace ConsoleApplicationDotNetBasics.ThreadingExamples { public class ManualResetEventSample { private readonly ManualResetEvent _manualReset = new ManualResetEvent(false); public void RunAll() { new Thread(Worker1).Start(); new Thread(Worker2).Start(); new Thread(Worker3).Start(); Console.WriteLine("All Threads Scheduled to RUN!. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId); Console.WriteLine("Main Thread is waiting for 15 seconds, observe 3 thread behaviour. All threads run once and stopped. Why? Because they call WaitOne() internally. They will wait until signals arrive, down below."); Thread.Sleep(15000); Console.WriteLine("1- Main will call ManualResetEvent.Set() in 5 seconds, watch out!"); Thread.Sleep(5000); _manualReset.Set(); Thread.Sleep(2000); Console.WriteLine("2- Main will call ManualResetEvent.Set() in 5 seconds, watch out!"); Thread.Sleep(5000); _manualReset.Set(); Thread.Sleep(2000); Console.WriteLine("3- Main will call ManualResetEvent.Set() in 5 seconds, watch out!"); Thread.Sleep(5000); _manualReset.Set(); Thread.Sleep(2000); Console.WriteLine("4- Main will call ManualResetEvent.Reset() in 5 seconds, watch out!"); Thread.Sleep(5000); _manualReset.Reset(); Thread.Sleep(2000); Console.WriteLine("It ran one more time. Why? Even Reset Sets the state of the event to nonsignaled (false), causing threads to block, this will initial the state, and threads will run again until they WaitOne()."); Thread.Sleep(10000); Console.WriteLine(); Console.WriteLine("This will go so on. Everytime you call Set(), ManualResetEvent will let ALL threads to run. So if you want synchronization between them, consider using AutoReset event, or simply user TPL (Task Parallel Library)."); Thread.Sleep(5000); Console.WriteLine("Main thread reached to end! ThreadId: {0}", Thread.CurrentThread.ManagedThreadId); } public void Worker1() { for (int i = 1; i &lt;= 10; i++) { Console.WriteLine("Worker1 is running {0}/10. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(5000); // this gets blocked until _autoReset gets signal _manualReset.WaitOne(); } Console.WriteLine("Worker1 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId); } public void Worker2() { for (int i = 1; i &lt;= 10; i++) { Console.WriteLine("Worker2 is running {0}/10. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(5000); // this gets blocked until _autoReset gets signal _manualReset.WaitOne(); } Console.WriteLine("Worker2 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId); } public void Worker3() { for (int i = 1; i &lt;= 10; i++) { Console.WriteLine("Worker3 is running {0}/10. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(5000); // this gets blocked until _autoReset gets signal _manualReset.WaitOne(); } Console.WriteLine("Worker3 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId); } } } </code></pre> <p></p> <p><strong>Auto Reset Event</strong></p> <pre><code>using System; using System.Threading; namespace ConsoleApplicationDotNetBasics.ThreadingExamples { public class AutoResetEventSample { private readonly AutoResetEvent _autoReset = new AutoResetEvent(false); public void RunAll() { new Thread(Worker1).Start(); new Thread(Worker2).Start(); new Thread(Worker3).Start(); Console.WriteLine("All Threads Scheduled to RUN!. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId); Console.WriteLine("Main Thread is waiting for 15 seconds, observe 3 thread behaviour. All threads run once and stopped. Why? Because they call WaitOne() internally. They will wait until signals arrive, down below."); Thread.Sleep(15000); Console.WriteLine("1- Main will call AutoResetEvent.Set() in 5 seconds, watch out!"); Thread.Sleep(5000); _autoReset.Set(); Thread.Sleep(2000); Console.WriteLine("2- Main will call AutoResetEvent.Set() in 5 seconds, watch out!"); Thread.Sleep(5000); _autoReset.Set(); Thread.Sleep(2000); Console.WriteLine("3- Main will call AutoResetEvent.Set() in 5 seconds, watch out!"); Thread.Sleep(5000); _autoReset.Set(); Thread.Sleep(2000); Console.WriteLine("4- Main will call AutoResetEvent.Reset() in 5 seconds, watch out!"); Thread.Sleep(5000); _autoReset.Reset(); Thread.Sleep(2000); Console.WriteLine("Nothing happened. Why? Becasuse Reset Sets the state of the event to nonsignaled, causing threads to block. Since they are already blocked, it will not affect anything."); Thread.Sleep(10000); Console.WriteLine("This will go so on. Everytime you call Set(), AutoResetEvent will let another thread to run. It will make it automatically, so you do not need to worry about thread running order, unless you want it manually!"); Thread.Sleep(5000); Console.WriteLine("Main thread reached to end! ThreadId: {0}", Thread.CurrentThread.ManagedThreadId); } public void Worker1() { for (int i = 1; i &lt;= 5; i++) { Console.WriteLine("Worker1 is running {0}/5. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(500); // this gets blocked until _autoReset gets signal _autoReset.WaitOne(); } Console.WriteLine("Worker1 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId); } public void Worker2() { for (int i = 1; i &lt;= 5; i++) { Console.WriteLine("Worker2 is running {0}/5. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(500); // this gets blocked until _autoReset gets signal _autoReset.WaitOne(); } Console.WriteLine("Worker2 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId); } public void Worker3() { for (int i = 1; i &lt;= 5; i++) { Console.WriteLine("Worker3 is running {0}/5. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(500); // this gets blocked until _autoReset gets signal _autoReset.WaitOne(); } Console.WriteLine("Worker3 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId); } } } </code></pre> <p></p> <br /><br /><br /><h3>回答8:</h3><br /><p><strong>AutoResetEvent</strong> maintains a boolean variable in memory. If the boolean variable is false then it blocks the thread and if the boolean variable is true it unblocks the thread.</p> <p>When we instantiate an AutoResetEvent object, we pass the default value of boolean value in the constructor. Below is the syntax of instantiate an AutoResetEvent object.</p> <pre><code>AutoResetEvent autoResetEvent = new AutoResetEvent(false); </code></pre> <p><strong>WaitOne method</strong></p> <p>This method blocks the current thread and wait for the signal by other thread. WaitOne method puts the current thread into a Sleep thread state. WaitOne method returns true if it receives the signal else returns false.</p> <pre><code>autoResetEvent.WaitOne(); </code></pre> <p>Second overload of WaitOne method wait for the specified number of seconds. If it does not get any signal thread continues its work.</p> <pre><code>static void ThreadMethod() { while(!autoResetEvent.WaitOne(TimeSpan.FromSeconds(2))) { Console.WriteLine("Continue"); Thread.Sleep(TimeSpan.FromSeconds(1)); } Console.WriteLine("Thread got signal"); } </code></pre> <p>We called WaitOne method by passing the 2 seconds as arguments. In the while loop, it wait for the signal for 2 seconds then it continues its work. When the thread got the signal WaitOne returns true and exits the loop and print the "Thread got signal".</p> <p><strong>Set method</strong></p> <p>AutoResetEvent Set method sent the signal to the waiting thread to proceed its work. Below is the syntax of calling Set method.</p> <pre><code>autoResetEvent.Set(); </code></pre> <hr /><p><strong>ManualResetEvent</strong> maintains a boolean variable in memory. When the boolean variable is false then it blocks all threads and when the boolean variable is true it unblocks all threads.</p> <p>When we instantiate a ManualResetEvent, we initialize it with default boolean value.</p> <pre><code>ManualResetEvent manualResetEvent = new ManualResetEvent(false); </code></pre> <p>In the above code, we initialize the ManualResetEvent with false value, that means all the threads which calls the WaitOne method will block until some thread calls the Set() method.</p> <p>If we initialize ManualResetEvent with true value, all the threads which calls the WaitOne method will not block and free to proceed further.</p> <p><strong>WaitOne Method</strong></p> <p>This method blocks the current thread and wait for the signal by other thread. It returns true if its receives a signal else returns false.</p> <p>Below is the syntax of calling WaitOne method.</p> <pre><code>manualResetEvent.WaitOne(); </code></pre> <p>In the second overload of WaitOne method, we can specify the time interval till the current thread wait for the signal. If within time internal, it does not receives a signal it returns false and goes into the next line of method.</p> <p>Below is the syntax of calling WaitOne method with time interval.</p> <pre><code>bool isSignalled = manualResetEvent.WaitOne(TimeSpan.FromSeconds(5)); </code></pre> <p>We have specify 5 seconds into the WaitOne method. If the manualResetEvent object does not receives a signal between 5 seconds, it set the isSignalled variable to false.</p> <p>Set Method</p> <p>This method is used for sending the signal to all waiting threads. Set() Method set the ManualResetEvent object boolean variable to true. All the waiting threads are unblocked and proceed further.</p> <p>Below is the syntax of calling Set() method.</p> <pre><code>manualResetEvent.Set(); </code></pre> <p><strong>Reset Method</strong></p> <p>Once we call the Set() method on the ManualResetEvent object, its boolean remains true. To reset the value we can use Reset() method. Reset method change the boolean value to false.</p> <p>Below is the syntax of calling Reset method.</p> <pre><code>manualResetEvent.Reset(); </code></pre> <p>We must immediately call Reset method after calling Set method if we want to send signal to threads multiple times.</p> <br /><br /><br /><h3>回答9:</h3><br /><p>Yes. This is absolutely correct.</p> <p>You could see ManualResetEvent as a way to indicate state. Something is on (Set) or off (Reset). An occurrence with some duration. Any thread waiting for that state to happen can proceed.</p> <p>An AutoResetEvent is more comparable to a signal. A one shot indication that something has happened. An occurrence without any duration. Typically but not necessarily the "something" that has happened is small and needs to be handled by a single thread - hence the automatic reset after a single thread have consumed the event. </p> <br /><br /><br /><h3>回答10:</h3><br /><p>Yes, thats right.</p> <p>You can get an idea by the usage of these two.</p> <p>If you need to tell that you are finished with some work and other (threads) waiting for this can now proceed, you should use ManualResetEvent.</p> <p>If you need to have mutual exclusive access to any resource, you should use AutoResetEvent.</p> <br /><br /><br /><h3>回答11:</h3><br /><p>If you want to understand AutoResetEvent and ManualResetEvent you need to understand not threading but interrupts!</p> <p>.NET wants to conjure up low-level programming the most distant possible.</p> <p>An interrupts is something used in low-level programming which equals to a signal that from low became high (or viceversa). When this happens the program interrupt its normal execution and move the execution pointer to the function that handles this <em>event</em>.</p> <p>The first thing to do when an interrupt happend is to <strong>reset</strong> its state, becosa the hardware works in this way:</p> <ol><li>a pin is connected to a signal and the hardware listen for it to change (the signal could have only two states).</li> <li>if the signal changes means that something happened and the hardware put a <strong>memory variable</strong> to the state happened (and it remain like this even if the signal change again).</li> <li>the program notice that variable change states and move the execution to a handling function.</li> <li>here the first thing to do, to be able to listen again this interrupt, is to <strong>reset</strong> this memory variable to the state not-happened.</li> </ol><p>This is the difference between ManualResetEvent and AutoResetEvent.<br /><strong>If a ManualResetEvent happen and I do not reset it, the next time it happens I will not be able to listen it.</strong></p> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/153877/what-is-the-difference-between-manualresetevent-and-autoresetevent-in-net</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/c" hreflang="zh-hans">c#</a></div> <div class="field--item"><a href="/tag/net" hreflang="zh-hans">.net</a></div> <div class="field--item"><a href="/tag/multithreading" hreflang="zh-hans">multithreading</a></div> <div class="field--item"><a href="/tag/autoresetevent" hreflang="zh-hans">autoresetevent</a></div> <div class="field--item"><a href="/tag/manualresetevent" hreflang="zh-hans">manualresetevent</a></div> </div> </div> Wed, 08 Jan 2020 09:22:35 +0000 醉酒当歌 3155700 at https://www.e-learn.cn What is the difference between ManualResetEvent and AutoResetEvent in .NET? https://www.e-learn.cn/topic/3155696 <span>What is the difference between ManualResetEvent and AutoResetEvent in .NET?</span> <span><span lang="" about="/user/24" typeof="schema:Person" property="schema:name" datatype="">Deadly</span></span> <span>2020-01-08 17:22:12</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>I have read the documentation on this and I think I understand. An AutoResetEvent resets when the code passes through <code>event.WaitOne()</code>, but a ManualResetEvent does not.</p> <p>Is this correct?</p> <br /><h3>回答1:</h3><br /><p>Yes. It's like the difference between a tollbooth and a door. The <code>ManualResetEvent</code> is the door, which needs to be closed (reset) manually. The <code>AutoResetEvent</code> is a tollbooth, allowing one car to go by and automatically closing before the next one can get through.</p> <br /><br /><br /><h3>回答2:</h3><br /><p>Just imagine that the <code>AutoResetEvent</code> executes <code>WaitOne()</code> and <code>Reset()</code> as a single atomic operation.</p> <br /><br /><br /><h3>回答3:</h3><br /><p>The short answer is yes. The most important difference is that an AutoResetEvent will only allow one single waiting thread to continue. A ManualResetEvent on the other hand will keep allowing threads, several at the same time even, to continue until you tell it to stop (Reset it).</p> <br /><br /><br /><h3>回答4:</h3><br /><blockquote> <p>Taken from C# 3.0 Nutshell book, by Joseph Albahari</p> </blockquote> <p>Threading in C# - Free E-Book</p> <p>A ManualResetEvent is a variation on AutoResetEvent. It differs in that it doesn't automatically reset after a thread is let through on a WaitOne call, and so functions like a gate: calling Set opens the gate, allowing any number of threads that WaitOne at the gate through; calling Reset closes the gate, causing, potentially, a queue of waiters to accumulate until its next opened.</p> <p>One could simulate this functionality with a boolean "gateOpen" field (declared with the volatile keyword) in combination with "spin-sleeping" – repeatedly checking the flag, and then sleeping for a short period of time.</p> <p>ManualResetEvents are sometimes used to signal that a particular operation is complete, or that a thread's completed initialization and is ready to perform work.</p> <br /><br /><br /><h3>回答5:</h3><br /><p>I created simple examples to clarify understanding of <code>ManualResetEvent</code> vs <code>AutoResetEvent</code>.</p> <p><code>AutoResetEvent</code>: lets assume you have 3 workers thread. If any of those threads will call <code>WaitOne()</code> all other 2 threads will stop execution and wait for signal. I am assuming they are using <code>WaitOne()</code>. It is like; if I do not work, nobody works. In first example you can see that</p> <pre><code>autoReset.Set(); Thread.Sleep(1000); autoReset.Set(); </code></pre> <p>When you call <code>Set()</code> all threads will work and wait for signal. After 1 second I am sending second signal and they execute and wait (<code>WaitOne()</code>). Think about these guys are soccer team players and if one player says I will wait until manager calls me, and others will wait until manager tells them to continue (<code>Set()</code>)</p> <pre><code>public class AutoResetEventSample { private AutoResetEvent autoReset = new AutoResetEvent(false); public void RunAll() { new Thread(Worker1).Start(); new Thread(Worker2).Start(); new Thread(Worker3).Start(); autoReset.Set(); Thread.Sleep(1000); autoReset.Set(); Console.WriteLine("Main thread reached to end."); } public void Worker1() { Console.WriteLine("Entered in worker 1"); for (int i = 0; i &lt; 5; i++) { Console.WriteLine("Worker1 is running {0}", i); Thread.Sleep(2000); autoReset.WaitOne(); } } public void Worker2() { Console.WriteLine("Entered in worker 2"); for (int i = 0; i &lt; 5; i++) { Console.WriteLine("Worker2 is running {0}", i); Thread.Sleep(2000); autoReset.WaitOne(); } } public void Worker3() { Console.WriteLine("Entered in worker 3"); for (int i = 0; i &lt; 5; i++) { Console.WriteLine("Worker3 is running {0}", i); Thread.Sleep(2000); autoReset.WaitOne(); } } } </code></pre> <p>In this example you can clearly see that when you first hit <code>Set()</code> it will let all threads go, then after 1 second it signals all threads to wait! As soon as you set them again regardless they are calling <code>WaitOne()</code> inside, they will keep running because you have to manually call <code>Reset()</code> to stop them all. </p> <pre><code>manualReset.Set(); Thread.Sleep(1000); manualReset.Reset(); Console.WriteLine("Press to release all threads."); Console.ReadLine(); manualReset.Set(); </code></pre> <p>It is more about Referee/Players relationship there regardless of any of the player is injured and wait for playing others will continue to work. If Referee says wait (<code>Reset()</code>) then all players will wait until next signal.</p> <pre><code>public class ManualResetEventSample { private ManualResetEvent manualReset = new ManualResetEvent(false); public void RunAll() { new Thread(Worker1).Start(); new Thread(Worker2).Start(); new Thread(Worker3).Start(); manualReset.Set(); Thread.Sleep(1000); manualReset.Reset(); Console.WriteLine("Press to release all threads."); Console.ReadLine(); manualReset.Set(); Console.WriteLine("Main thread reached to end."); } public void Worker1() { Console.WriteLine("Entered in worker 1"); for (int i = 0; i &lt; 5; i++) { Console.WriteLine("Worker1 is running {0}", i); Thread.Sleep(2000); manualReset.WaitOne(); } } public void Worker2() { Console.WriteLine("Entered in worker 2"); for (int i = 0; i &lt; 5; i++) { Console.WriteLine("Worker2 is running {0}", i); Thread.Sleep(2000); manualReset.WaitOne(); } } public void Worker3() { Console.WriteLine("Entered in worker 3"); for (int i = 0; i &lt; 5; i++) { Console.WriteLine("Worker3 is running {0}", i); Thread.Sleep(2000); manualReset.WaitOne(); } } } </code></pre> <br /><br /><br /><h3>回答6:</h3><br /><p><code>autoResetEvent.WaitOne()</code> </p> <p>is similar to</p> <pre><code>try { manualResetEvent.WaitOne(); } finally { manualResetEvent.Reset(); } </code></pre> <p>as an atomic operation</p> <br /><br /><br /><h3>回答7:</h3><br /><p>OK, normally it does not a good practice to add 2 answers in same thread, but I did not want to edit/delete my previous answer, since it can help on another manner.</p> <p>Now, I created, much more comprehensive, and easy to understand, run-to-learn console app snippet below.</p> <p>Just run the examples on two different consoles, and observe behaviour. You will get much more clear idea there what is happening behind the scenes.</p> <p><strong>Manual Reset Event</strong></p> <pre><code>using System; using System.Threading; namespace ConsoleApplicationDotNetBasics.ThreadingExamples { public class ManualResetEventSample { private readonly ManualResetEvent _manualReset = new ManualResetEvent(false); public void RunAll() { new Thread(Worker1).Start(); new Thread(Worker2).Start(); new Thread(Worker3).Start(); Console.WriteLine("All Threads Scheduled to RUN!. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId); Console.WriteLine("Main Thread is waiting for 15 seconds, observe 3 thread behaviour. All threads run once and stopped. Why? Because they call WaitOne() internally. They will wait until signals arrive, down below."); Thread.Sleep(15000); Console.WriteLine("1- Main will call ManualResetEvent.Set() in 5 seconds, watch out!"); Thread.Sleep(5000); _manualReset.Set(); Thread.Sleep(2000); Console.WriteLine("2- Main will call ManualResetEvent.Set() in 5 seconds, watch out!"); Thread.Sleep(5000); _manualReset.Set(); Thread.Sleep(2000); Console.WriteLine("3- Main will call ManualResetEvent.Set() in 5 seconds, watch out!"); Thread.Sleep(5000); _manualReset.Set(); Thread.Sleep(2000); Console.WriteLine("4- Main will call ManualResetEvent.Reset() in 5 seconds, watch out!"); Thread.Sleep(5000); _manualReset.Reset(); Thread.Sleep(2000); Console.WriteLine("It ran one more time. Why? Even Reset Sets the state of the event to nonsignaled (false), causing threads to block, this will initial the state, and threads will run again until they WaitOne()."); Thread.Sleep(10000); Console.WriteLine(); Console.WriteLine("This will go so on. Everytime you call Set(), ManualResetEvent will let ALL threads to run. So if you want synchronization between them, consider using AutoReset event, or simply user TPL (Task Parallel Library)."); Thread.Sleep(5000); Console.WriteLine("Main thread reached to end! ThreadId: {0}", Thread.CurrentThread.ManagedThreadId); } public void Worker1() { for (int i = 1; i &lt;= 10; i++) { Console.WriteLine("Worker1 is running {0}/10. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(5000); // this gets blocked until _autoReset gets signal _manualReset.WaitOne(); } Console.WriteLine("Worker1 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId); } public void Worker2() { for (int i = 1; i &lt;= 10; i++) { Console.WriteLine("Worker2 is running {0}/10. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(5000); // this gets blocked until _autoReset gets signal _manualReset.WaitOne(); } Console.WriteLine("Worker2 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId); } public void Worker3() { for (int i = 1; i &lt;= 10; i++) { Console.WriteLine("Worker3 is running {0}/10. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(5000); // this gets blocked until _autoReset gets signal _manualReset.WaitOne(); } Console.WriteLine("Worker3 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId); } } } </code></pre> <p></p> <p><strong>Auto Reset Event</strong></p> <pre><code>using System; using System.Threading; namespace ConsoleApplicationDotNetBasics.ThreadingExamples { public class AutoResetEventSample { private readonly AutoResetEvent _autoReset = new AutoResetEvent(false); public void RunAll() { new Thread(Worker1).Start(); new Thread(Worker2).Start(); new Thread(Worker3).Start(); Console.WriteLine("All Threads Scheduled to RUN!. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId); Console.WriteLine("Main Thread is waiting for 15 seconds, observe 3 thread behaviour. All threads run once and stopped. Why? Because they call WaitOne() internally. They will wait until signals arrive, down below."); Thread.Sleep(15000); Console.WriteLine("1- Main will call AutoResetEvent.Set() in 5 seconds, watch out!"); Thread.Sleep(5000); _autoReset.Set(); Thread.Sleep(2000); Console.WriteLine("2- Main will call AutoResetEvent.Set() in 5 seconds, watch out!"); Thread.Sleep(5000); _autoReset.Set(); Thread.Sleep(2000); Console.WriteLine("3- Main will call AutoResetEvent.Set() in 5 seconds, watch out!"); Thread.Sleep(5000); _autoReset.Set(); Thread.Sleep(2000); Console.WriteLine("4- Main will call AutoResetEvent.Reset() in 5 seconds, watch out!"); Thread.Sleep(5000); _autoReset.Reset(); Thread.Sleep(2000); Console.WriteLine("Nothing happened. Why? Becasuse Reset Sets the state of the event to nonsignaled, causing threads to block. Since they are already blocked, it will not affect anything."); Thread.Sleep(10000); Console.WriteLine("This will go so on. Everytime you call Set(), AutoResetEvent will let another thread to run. It will make it automatically, so you do not need to worry about thread running order, unless you want it manually!"); Thread.Sleep(5000); Console.WriteLine("Main thread reached to end! ThreadId: {0}", Thread.CurrentThread.ManagedThreadId); } public void Worker1() { for (int i = 1; i &lt;= 5; i++) { Console.WriteLine("Worker1 is running {0}/5. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(500); // this gets blocked until _autoReset gets signal _autoReset.WaitOne(); } Console.WriteLine("Worker1 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId); } public void Worker2() { for (int i = 1; i &lt;= 5; i++) { Console.WriteLine("Worker2 is running {0}/5. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(500); // this gets blocked until _autoReset gets signal _autoReset.WaitOne(); } Console.WriteLine("Worker2 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId); } public void Worker3() { for (int i = 1; i &lt;= 5; i++) { Console.WriteLine("Worker3 is running {0}/5. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(500); // this gets blocked until _autoReset gets signal _autoReset.WaitOne(); } Console.WriteLine("Worker3 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId); } } } </code></pre> <p></p> <br /><br /><br /><h3>回答8:</h3><br /><p><strong>AutoResetEvent</strong> maintains a boolean variable in memory. If the boolean variable is false then it blocks the thread and if the boolean variable is true it unblocks the thread.</p> <p>When we instantiate an AutoResetEvent object, we pass the default value of boolean value in the constructor. Below is the syntax of instantiate an AutoResetEvent object.</p> <pre><code>AutoResetEvent autoResetEvent = new AutoResetEvent(false); </code></pre> <p><strong>WaitOne method</strong></p> <p>This method blocks the current thread and wait for the signal by other thread. WaitOne method puts the current thread into a Sleep thread state. WaitOne method returns true if it receives the signal else returns false.</p> <pre><code>autoResetEvent.WaitOne(); </code></pre> <p>Second overload of WaitOne method wait for the specified number of seconds. If it does not get any signal thread continues its work.</p> <pre><code>static void ThreadMethod() { while(!autoResetEvent.WaitOne(TimeSpan.FromSeconds(2))) { Console.WriteLine("Continue"); Thread.Sleep(TimeSpan.FromSeconds(1)); } Console.WriteLine("Thread got signal"); } </code></pre> <p>We called WaitOne method by passing the 2 seconds as arguments. In the while loop, it wait for the signal for 2 seconds then it continues its work. When the thread got the signal WaitOne returns true and exits the loop and print the "Thread got signal".</p> <p><strong>Set method</strong></p> <p>AutoResetEvent Set method sent the signal to the waiting thread to proceed its work. Below is the syntax of calling Set method.</p> <pre><code>autoResetEvent.Set(); </code></pre> <hr /><p><strong>ManualResetEvent</strong> maintains a boolean variable in memory. When the boolean variable is false then it blocks all threads and when the boolean variable is true it unblocks all threads.</p> <p>When we instantiate a ManualResetEvent, we initialize it with default boolean value.</p> <pre><code>ManualResetEvent manualResetEvent = new ManualResetEvent(false); </code></pre> <p>In the above code, we initialize the ManualResetEvent with false value, that means all the threads which calls the WaitOne method will block until some thread calls the Set() method.</p> <p>If we initialize ManualResetEvent with true value, all the threads which calls the WaitOne method will not block and free to proceed further.</p> <p><strong>WaitOne Method</strong></p> <p>This method blocks the current thread and wait for the signal by other thread. It returns true if its receives a signal else returns false.</p> <p>Below is the syntax of calling WaitOne method.</p> <pre><code>manualResetEvent.WaitOne(); </code></pre> <p>In the second overload of WaitOne method, we can specify the time interval till the current thread wait for the signal. If within time internal, it does not receives a signal it returns false and goes into the next line of method.</p> <p>Below is the syntax of calling WaitOne method with time interval.</p> <pre><code>bool isSignalled = manualResetEvent.WaitOne(TimeSpan.FromSeconds(5)); </code></pre> <p>We have specify 5 seconds into the WaitOne method. If the manualResetEvent object does not receives a signal between 5 seconds, it set the isSignalled variable to false.</p> <p>Set Method</p> <p>This method is used for sending the signal to all waiting threads. Set() Method set the ManualResetEvent object boolean variable to true. All the waiting threads are unblocked and proceed further.</p> <p>Below is the syntax of calling Set() method.</p> <pre><code>manualResetEvent.Set(); </code></pre> <p><strong>Reset Method</strong></p> <p>Once we call the Set() method on the ManualResetEvent object, its boolean remains true. To reset the value we can use Reset() method. Reset method change the boolean value to false.</p> <p>Below is the syntax of calling Reset method.</p> <pre><code>manualResetEvent.Reset(); </code></pre> <p>We must immediately call Reset method after calling Set method if we want to send signal to threads multiple times.</p> <br /><br /><br /><h3>回答9:</h3><br /><p>Yes. This is absolutely correct.</p> <p>You could see ManualResetEvent as a way to indicate state. Something is on (Set) or off (Reset). An occurrence with some duration. Any thread waiting for that state to happen can proceed.</p> <p>An AutoResetEvent is more comparable to a signal. A one shot indication that something has happened. An occurrence without any duration. Typically but not necessarily the "something" that has happened is small and needs to be handled by a single thread - hence the automatic reset after a single thread have consumed the event. </p> <br /><br /><br /><h3>回答10:</h3><br /><p>Yes, thats right.</p> <p>You can get an idea by the usage of these two.</p> <p>If you need to tell that you are finished with some work and other (threads) waiting for this can now proceed, you should use ManualResetEvent.</p> <p>If you need to have mutual exclusive access to any resource, you should use AutoResetEvent.</p> <br /><br /><br /><h3>回答11:</h3><br /><p>If you want to understand AutoResetEvent and ManualResetEvent you need to understand not threading but interrupts!</p> <p>.NET wants to conjure up low-level programming the most distant possible.</p> <p>An interrupts is something used in low-level programming which equals to a signal that from low became high (or viceversa). When this happens the program interrupt its normal execution and move the execution pointer to the function that handles this <em>event</em>.</p> <p>The first thing to do when an interrupt happend is to <strong>reset</strong> its state, becosa the hardware works in this way:</p> <ol><li>a pin is connected to a signal and the hardware listen for it to change (the signal could have only two states).</li> <li>if the signal changes means that something happened and the hardware put a <strong>memory variable</strong> to the state happened (and it remain like this even if the signal change again).</li> <li>the program notice that variable change states and move the execution to a handling function.</li> <li>here the first thing to do, to be able to listen again this interrupt, is to <strong>reset</strong> this memory variable to the state not-happened.</li> </ol><p>This is the difference between ManualResetEvent and AutoResetEvent.<br /><strong>If a ManualResetEvent happen and I do not reset it, the next time it happens I will not be able to listen it.</strong></p> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/153877/what-is-the-difference-between-manualresetevent-and-autoresetevent-in-net</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/c" hreflang="zh-hans">c#</a></div> <div class="field--item"><a href="/tag/net" hreflang="zh-hans">.net</a></div> <div class="field--item"><a href="/tag/multithreading" hreflang="zh-hans">multithreading</a></div> <div class="field--item"><a href="/tag/autoresetevent" hreflang="zh-hans">autoresetevent</a></div> <div class="field--item"><a href="/tag/manualresetevent" hreflang="zh-hans">manualresetevent</a></div> </div> </div> Wed, 08 Jan 2020 09:22:12 +0000 Deadly 3155696 at https://www.e-learn.cn Win32 reset event like synchronization class with boost C++ https://www.e-learn.cn/topic/2756278 <span>Win32 reset event like synchronization class with boost C++</span> <span><span lang="" about="/user/70" typeof="schema:Person" property="schema:name" datatype="">蹲街弑〆低调</span></span> <span>2019-12-22 08:20:35</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>I need some mechanism reminiscent of Win32 reset events that I can check via functions having the same semantics with WaitForSingleObject() and WaitForMultipleObjects() (Only need the ..SingleObject() version for the moment) . But I am targeting multiple platforms so all I have is boost::threads (AFAIK) . I came up with the following class and wanted to ask about the potential problems and whether it is up to the task or not. Thanks in advance.</p> <pre><code>class reset_event { bool flag, auto_reset; boost::condition_variable cond_var; boost::mutex mx_flag; public: reset_event(bool _auto_reset = false) : flag(false), auto_reset(_auto_reset) { } void wait() { boost::unique_lock&lt;boost::mutex&gt; LOCK(mx_flag); if (flag) return; cond_var.wait(LOCK); if (auto_reset) flag = false; } bool wait(const boost::posix_time::time_duration&amp; dur) { boost::unique_lock&lt;boost::mutex&gt; LOCK(mx_flag); bool ret = cond_var.timed_wait(LOCK, dur) || flag; if (auto_reset &amp;&amp; ret) flag = false; return ret; } void set() { boost::lock_guard&lt;boost::mutex&gt; LOCK(mx_flag); flag = true; cond_var.notify_all(); } void reset() { boost::lock_guard&lt;boost::mutex&gt; LOCK(mx_flag); flag = false; } }; </code></pre> <p>Example usage;</p> <pre><code>reset_event terminate_thread; void fn_thread() { while(!terminate_thread.wait(boost::posix_time::milliseconds(10))) { std::cout &lt;&lt; "working..." &lt;&lt; std::endl; boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); } std::cout &lt;&lt; "thread terminated" &lt;&lt; std::endl; } int main() { boost::thread worker(fn_thread); boost::this_thread::sleep(boost::posix_time::seconds(1)); terminate_thread.set(); worker.join(); return 0; } </code></pre> <p><strong>EDIT</strong></p> <p>I have fixed the code according to Michael Burr's suggestions. My "very simple" tests indicate no problems.</p> <pre><code>class reset_event { bool flag, auto_reset; boost::condition_variable cond_var; boost::mutex mx_flag; public: explicit reset_event(bool _auto_reset = false) : flag(false), auto_reset(_auto_reset) { } void wait() { boost::unique_lock&lt;boost::mutex&gt; LOCK(mx_flag); if (flag) { if (auto_reset) flag = false; return; } do { cond_var.wait(LOCK); } while(!flag); if (auto_reset) flag = false; } bool wait(const boost::posix_time::time_duration&amp; dur) { boost::unique_lock&lt;boost::mutex&gt; LOCK(mx_flag); if (flag) { if (auto_reset) flag = false; return true; } bool ret = cond_var.timed_wait(LOCK, dur); if (ret &amp;&amp; flag) { if (auto_reset) flag = false; return true; } return false; } void set() { boost::lock_guard&lt;boost::mutex&gt; LOCK(mx_flag); flag = true; cond_var.notify_all(); } void reset() { boost::lock_guard&lt;boost::mutex&gt; LOCK(mx_flag); flag = false; } }; </code></pre> <br /><h3>回答1:</h3><br /><p>A few things that you'll want to check/fix (note - I'm by no means saying that these are the only things - I've only had a quick look):</p> <ul><li><p>in your <code>wait()</code> function, you don't reset on an already signaled event if it's set up for <code>auto_reset</code>:</p> <pre><code> void wait() { boost::unique_lock&lt;boost::mutex&gt; LOCK(mx_flag); if (flag) { if (auto_reset) flag = false; // &lt;-- I think you need this return; } cond_var.wait(LOCK); if (auto_reset) flag = false; } </code></pre></li> <li><p>in <code>wait(const boost::posix_time::time_duration&amp; dur)</code> you should check <code>flag</code> <em>before</em> waiting on the condition variable. </p></li> <li><p>in both <code>wait</code> functions, if you wait on the condition variable, you might need to recheck the flag to make sure that some other thread hasn't reset the event in the meantime. This is particularly true for auto_reset events which should only free up a single waiter even when multiple threads are waiting on the event.</p></li> </ul><br /><br /><br /><h3>回答2:</h3><br /><p>Here is my version which was slightly tweaked to achieve the following.</p> <ul><li>No blocking the producer using set(),reset(),etc instead it counts the number of "releases" rather than losing the 1:1 mapping after the boolean condition is true.</li> <li>Allows outside callers to specify the mutex for wait(), it's often an outside resource anyways in my use scenarios and can be separate from the internal mutex.</li> <li>Moved set(),reset_one(),reset_all() calls to an internal mutex, now they don't block when repeatedly called before the consumer calls wait().</li> </ul><p>Now my loading thread can queue up multiple long-lived requests without dropping any tasks while busy processing. </p> <p>Progression in my project Using....</p> <p><strong>Boost Condition Variable:</strong> -&gt; send 3 load requests, thread is busy and only sees 1 or 2.<br /><strong>Posted Answer using Bool:</strong> -&gt; send 3 load requests, producer blocks on 2nd request due to shared mutex. producer doesn't unblock until 1st load request processed.<br /><strong>My version</strong> -&gt; send 3 load requests, producer immediately returns from all 3, consumer sees 3 load request slowly but surely :)<br /></p> <p>Hopefully it helps someone out there.</p> <pre> class cNonLossyCondition { bool flag, auto_reset; boost::condition_variable cond_var; int lost_signals; boost::mutex internal_mutex; public: cNonLossyCondition(bool _auto_reset) { this-&gt;flag = false; this-&gt;auto_reset = auto_reset; this-&gt;lost_signals = 0; } void wait(boost::mutex* mx_flag) { boost::unique_lock LOCK(*mx_flag); if (flag) { if (auto_reset) this-&gt;reset_one(); return; } do { cond_var.wait(LOCK); } while(!flag); if (auto_reset) this-&gt;reset_one(); } bool wait(boost::mutex* mx_flag,const boost::posix_time::time_duration&amp; dur) { boost::unique_lock LOCK(*mx_flag); if (flag) { if (auto_reset) this-&gt;reset_one(); return true; } bool ret = cond_var.timed_wait(LOCK, dur); if (ret &amp;&amp; flag) { if (auto_reset) this-&gt;reset_one(); return true; } return false; } void set() { boost::lock_guard LOCK(this-&gt;internal_mutex); flag = true; if (this-&gt;lost_signals lost_signals = 1; //already incremented } else { this-&gt;lost_signals = this-&gt;lost_signals + 1; } cond_var.notify_all(); } void reset_one() { boost::lock_guard LOCK(this-&gt;internal_mutex); this-&gt;lost_signals = this-&gt;lost_signals - 1; if (this-&gt;lost_signals lost_signals = 0; flag = false; } } void reset_all() { boost::lock_guard LOCK(this-&gt;internal_mutex); flag = false; this-&gt;lost_signals = 0; } }; </pre> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/4692717/win32-reset-event-like-synchronization-class-with-boost-c</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/c-0" hreflang="zh-hans">c++</a></div> <div class="field--item"><a href="/tag/multithreading" hreflang="zh-hans">multithreading</a></div> <div class="field--item"><a href="/tag/synchronization" hreflang="zh-hans">synchronization</a></div> <div class="field--item"><a href="/tag/cross-platform" hreflang="zh-hans">cross-platform</a></div> <div class="field--item"><a href="/tag/autoresetevent" hreflang="zh-hans">autoresetevent</a></div> </div> </div> Sun, 22 Dec 2019 00:20:35 +0000 蹲街弑〆低调 2756278 at https://www.e-learn.cn Synchronizing two threads with AutoResetEvent https://www.e-learn.cn/topic/2633679 <span>Synchronizing two threads with AutoResetEvent</span> <span><span lang="" about="/user/158" typeof="schema:Person" property="schema:name" datatype="">放肆的年华</span></span> <span>2019-12-19 05:29:48</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>I'm trying to implement <code>AutoResetEvent</code>. For the purpose I use a very simple class :</p> <pre><code>public class MyThreadTest { static readonly AutoResetEvent thread1Step = new AutoResetEvent(false); static readonly AutoResetEvent thread2Step = new AutoResetEvent(false); void DisplayThread1() { while (true) { Console.WriteLine("Display Thread 1"); Thread.Sleep(1000); thread1Step.Set(); thread2Step.WaitOne(); } } void DisplayThread2() { while (true) { Console.WriteLine("Display Thread 2"); Thread.Sleep(1000); thread2Step.Set(); thread1Step.WaitOne(); } } void CreateThreads() { // construct two threads for our demonstration; Thread thread1 = new Thread(new ThreadStart(DisplayThread1)); Thread thread2 = new Thread(new ThreadStart(DisplayThread2)); // start them thread1.Start(); thread2.Start(); } public static void Main() { MyThreadTest StartMultiThreads = new MyThreadTest(); StartMultiThreads.CreateThreads(); } } </code></pre> <p>But this is not working. Th usage seem very straight-forward so I would appreciate if someone is able to show me what's wrong and where is the problem with the logic which i implement here.</p> <br /><h3>回答1:</h3><br /><p>The question is not very clear but I'm guessing you're expecting it to display 1,2,1,2... </p> <p>Then try this:</p> <pre><code>public class MyThreadTest { static readonly AutoResetEvent thread1Step = new AutoResetEvent(false); static readonly AutoResetEvent thread2Step = new AutoResetEvent(true); void DisplayThread1() { while (true) { thread2Step.WaitOne(); Console.WriteLine("Display Thread 1"); Thread.Sleep(1000); thread1Step.Set(); } } void DisplayThread2() { while (true) { thread1Step.WaitOne(); Console.WriteLine("Display Thread 2"); Thread.Sleep(1000); thread2Step.Set(); } } void CreateThreads() { // construct two threads for our demonstration; Thread thread1 = new Thread(new ThreadStart(DisplayThread1)); Thread thread2 = new Thread(new ThreadStart(DisplayThread2)); // start them thread1.Start(); thread2.Start(); } public static void Main() { MyThreadTest StartMultiThreads = new MyThreadTest(); StartMultiThreads.CreateThreads(); } } </code></pre> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/14481664/synchronizing-two-threads-with-autoresetevent</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/c" hreflang="zh-hans">c#</a></div> <div class="field--item"><a href="/tag/multithreading" hreflang="zh-hans">multithreading</a></div> <div class="field--item"><a href="/tag/autoresetevent" hreflang="zh-hans">autoresetevent</a></div> </div> </div> Wed, 18 Dec 2019 21:29:48 +0000 放肆的年华 2633679 at https://www.e-learn.cn AutoResetEvent vs. boolean to stop a thread https://www.e-learn.cn/topic/2575671 <span>AutoResetEvent vs. boolean to stop a thread</span> <span><span lang="" about="/user/35" typeof="schema:Person" property="schema:name" datatype="">99封情书</span></span> <span>2019-12-18 01:12:12</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>I have an object in a worker thread, which I can instruct to stop running. I can implement this using a bool or an AutoResetEvent:</p> <p>boolean:</p> <pre><code>private volatile bool _isRunning; public void Run() { while (_isRunning) { doWork(); Thread.Sleep(1000); } } </code></pre> <p>AutoResetEvent:</p> <pre><code>private AutoResetEvent _stop; public void Run() { do { doWork(); } while (!_stop.WaitOne(1000)); } </code></pre> <p>The <code>Stop()</code> method would then set <code>_isRunning</code> to false, or call <code>_stop.Set()</code>.</p> <p>Apart from that the solution with AutoResetEvent may stop a little faster, is there any difference between these method? Is one "better" than the other?</p> <br /><h3>回答1:</h3><br /><p>C# <em>volatile</em> does not provide all the guaranties. It <em>may</em> still read stale data. Better to use underlying OS synchronisation mechanism as it provides much stronger guaranties.</p> <p>All this in great depth discussed by Eric Lippert (really worth reading), here is short quote:</p> <blockquote> <p>In C#, <i>"volatile" means not only "make sure that the compiler and the jitter do not perform any code reordering or register caching optimizations on this variable"</i>. It also means <i>"tell the processors to do whatever it is they need to do to ensure that I am reading the latest value, even if that means halting other processors and making them synchronize main memory with their caches"</i>.</p> <p>Actually, that last bit is a lie. The true semantics of volatile reads and writes are considerably more complex than I've outlined here; in fact <b>they do not actually guarantee that every processor stops what it is doing</b> and updates caches to/from main memory. Rather, <b>they provide weaker guarantees about how memory accesses before and after reads and writes may be observed to be ordered with respect to each other.</b> Certain operations such as creating a new thread, entering a lock, or using one of the Interlocked family of methods introduce stronger guarantees about observation of ordering. If you want more details, read sections 3.10 and 10.5.3 of the C# 4.0 specification.</p> <p>Frankly, <b>I discourage you from ever making a volatile field</b>. Volatile fields are a sign that you are doing something downright crazy: you're attempting to read and write the same value on two different threads without putting a lock in place. Locks guarantee that memory read or modified inside the lock is observed to be consistent, locks guarantee that only one thread accesses a given hunk of memory at a time, and so on.</p> </blockquote> <br /><br /><br /><h3>回答2:</h3><br /><p>Volatile isn't good enough, but practically it will always work because the operating system scheduler will always take a lock eventually. And will work well on a core with a strong memory model, like x86 which burns a lot of juice to keep caches synchronized between cores.</p> <p>So what really only matters is how quickly a thread will respond to the stop request. It is easy to measure, just start a Stopwatch in the control thread and record the time after the while loop in the worker thread. The results I measured from repeating taking 1000 samples and taking the average, repeated 10 times:</p> <pre><code>volatile bool, x86: 550 nanoseconds volatile bool, x64: 550 nanoseconds ManualResetEvent, x86: 2270 nanoseconds ManualResetEvent, x64: 2250 nanoseconds AutoResetEvent, x86: 2500 nanoseconds AutoResetEvent, x64: 2100 nanoseconds ManualResetEventSlim, x86: 650 nanoseconds ManualResetEventSlim, x64: 630 nanoseconds </code></pre> <p>Beware that the results for volatile bool are very unlikely to look that well on a processor with a weak memory model, like ARM or Itanium. I don't have one to test.</p> <p>Clearly it looks like you want to favor ManualResetEventSlim, giving good perf and a guarantee.</p> <p>One note with these results, they were measured with the worker thread running a hot loop, constantly testing the stop condition and not doing any other work. That's not exactly a good match with real code, a thread won't typically check the stop condition that often. Which makes the differences between these techniques largely inconsequential.</p> <br /><br /><br /><h3>回答3:</h3><br /><p>IMHO the <code>AutoResetEvent</code> is better, because you can't forget the crucial <code>volatile</code> keyword in this case.</p> <br /><br /><br /><h3>回答4:</h3><br /><p>Before using the <code>volatile</code> keyword, you should read this and, I guess, when researching multi-threading you could read the whole http://www.albahari.com/threading/ article.</p> <p>It explains the subtleties of the <code>volatile</code> keyword and why its behaviour can be unexpected.</p> <hr /><p>You'll note, that when using <code>volatile</code>, reads and writes can get reordered which could result in an extra iteration in closely concurrent situations. In this case you may have to wait for around one extra second.</p> <hr /><p>After looking, I don't think your code works for several reasons,</p> <p>The "boolean:" snippet always sleeps for approximately a second, probably not what you want.</p> <p>The "AutoResetEvent:" snippet doesen't instantiate <code>_stop</code> and, will always run <code>doWork()</code> at least once.</p> <br /><br /><br /><h3>回答5:</h3><br /><p>It depends if the above snippet is all you are doing or not. The AutoReset event, as its name suggests, gets reset after the WaitOne is passed. This means that you could then use it again straightaway, rather than with the bool, having to set it back to true.</p> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/11953234/autoresetevent-vs-boolean-to-stop-a-thread</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/c" hreflang="zh-hans">c#</a></div> <div class="field--item"><a href="/tag/multithreading" hreflang="zh-hans">multithreading</a></div> <div class="field--item"><a href="/tag/autoresetevent" hreflang="zh-hans">autoresetevent</a></div> </div> </div> Tue, 17 Dec 2019 17:12:12 +0000 99封情书 2575671 at https://www.e-learn.cn Unstable application uses SqlDependency. Several states and errors https://www.e-learn.cn/topic/2297467 <span>Unstable application uses SqlDependency. Several states and errors</span> <span><span lang="" about="/user/42" typeof="schema:Person" property="schema:name" datatype="">我的未来我决定</span></span> <span>2019-12-11 18:59:22</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>I have a windows application using SqlDependency running at separated thread pool, this application represents a log monitor UI get the latest rows added in a specific table in the database and view it in a DataGridView. You can see the application source code from this LINK, or follow this script.</p> <pre><code> const string tableName = "OutgoingLog"; const string statusMessage = "{0} changes have occurred."; int changeCount = 0; private static DataSet dataToWatch = null; private static SqlConnection connection = null; private static SqlCommand command = null; public frmMain() { InitializeComponent(); } private bool CanRequestNotifications() { // In order to use the callback feature of the // SqlDependency, the application must have // the SqlClientPermission permission. try { SqlClientPermission perm = new SqlClientPermission(PermissionState.Unrestricted); perm.Demand(); return true; } catch { return false; } } private void dependency_OnChange(object sender, SqlNotificationEventArgs e) { // This event will occur on a thread pool thread. // Updating the UI from a worker thread is not permitted. // The following code checks to see if it is safe to // update the UI. ISynchronizeInvoke i = (ISynchronizeInvoke)this; // If InvokeRequired returns True, the code // is executing on a worker thread. if (i.InvokeRequired) { // Create a delegate to perform the thread switch. OnChangeEventHandler tempDelegate = new OnChangeEventHandler(dependency_OnChange); object[] args = { sender, e }; // Marshal the data from the worker thread // to the UI thread. i.BeginInvoke(tempDelegate, args); return; } // Remove the handler, since it is only good // for a single notification. SqlDependency dependency = (SqlDependency)sender; dependency.OnChange -= dependency_OnChange; // At this point, the code is executing on the // UI thread, so it is safe to update the UI. ++changeCount; lblChanges.Text = String.Format(statusMessage, changeCount); // Reload the dataset that is bound to the grid. GetData(); } AutoResetEvent running = new AutoResetEvent(true); private void GetData() { // Start the retrieval of data on another thread to let the UI thread free ThreadPool.QueueUserWorkItem(o =&gt; { running.WaitOne(); // Empty the dataset so that there is only // one batch of data displayed. dataToWatch.Clear(); // Make sure the command object does not already have // a notification object associated with it. command.Notification = null; // Create and bind the SqlDependency object // to the command object. SqlDependency dependency = new SqlDependency(command); dependency.OnChange += new OnChangeEventHandler(dependency_OnChange); using (SqlDataAdapter adapter = new SqlDataAdapter(command)) { adapter.Fill(dataToWatch, tableName); try { running.Set(); } finally { // Update the UI dgv.Invoke(new Action(() =&gt; { dgv.DataSource = dataToWatch; dgv.DataMember = tableName; //dgv.FirstDisplayedScrollingRowIndex = dgv.Rows.Count - 1; })); } } }); } private void btnAction_Click(object sender, EventArgs e) { changeCount = 0; lblChanges.Text = String.Format(statusMessage, changeCount); // Remove any existing dependency connection, then create a new one. SqlDependency.Stop("Server=.; Database=SMS_Tank_Log;UID=sa;PWD=hana;MultipleActiveResultSets=True"); SqlDependency.Start("Server=.; Database=SMS_Tank_Log;UID=sa;PWD=hana;MultipleActiveResultSets=True"); if (connection == null) { connection = new SqlConnection("Server=.; Database=SMS_Tank_Log;UID=sa;PWD=hana;MultipleActiveResultSets=True"); } if (command == null) { command = new SqlCommand("select * from OutgoingLog", connection); //SqlParameter prm = // new SqlParameter("@Quantity", SqlDbType.Int); //prm.Direction = ParameterDirection.Input; //prm.DbType = DbType.Int32; //prm.Value = 100; //command.Parameters.Add(prm); } if (dataToWatch == null) { dataToWatch = new DataSet(); } GetData(); } private void frmMain_Load(object sender, EventArgs e) { btnAction.Enabled = CanRequestNotifications(); } private void frmMain_FormClosing(object sender, FormClosingEventArgs e) { SqlDependency.Stop("Server=.; Database=SMS_Tank_Log;UID=sa;PWD=hana;MultipleActiveResultSets=True"); } </code></pre> <p><strong>The problem:</strong> I have many situations of errors, <strong>(images in the first comment)</strong></p> <p><strong>(No. 1)</strong>: I got this error dialog, and I don't know its reason.</p> <p><strong>(No. 2)</strong>: I got nothing in my grid view (No errors, and no data).</p> <p><strong>(No. 3)</strong>: I got only columns names and no rows, although the table has rows.</p> <p>I need help please.</p> <br /><h3>回答1:</h3><br /><p>I may be wrong but a <em>DataSet</em> does not seem to have <strong>notification</strong> capability so the <em>DataGridView</em> may be surprised if you change it behind its back.</p> <p>You could try to explicitly show your're changing the data source by first setting it to null:</p> <pre><code>dgv.DataSource = null; dgv.DataSource = dataToWatch; dgv.DataMember = tableName; </code></pre> <p>It's worth a try...</p> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/17051595/unstable-application-uses-sqldependency-several-states-and-errors</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/threadpool" hreflang="zh-hans">threadpool</a></div> <div class="field--item"><a href="/tag/sqldependency" hreflang="zh-hans">sqldependency</a></div> <div class="field--item"><a href="/tag/autoresetevent" hreflang="zh-hans">autoresetevent</a></div> <div class="field--item"><a href="/tag/waitone" hreflang="zh-hans">waitone</a></div> </div> </div> Wed, 11 Dec 2019 10:59:22 +0000 我的未来我决定 2297467 at https://www.e-learn.cn Wait for WebBrowser DocumentCompleted using AutoResetEvent https://www.e-learn.cn/topic/2252895 <span>Wait for WebBrowser DocumentCompleted using AutoResetEvent</span> <span><span lang="" about="/user/135" typeof="schema:Person" property="schema:name" datatype="">纵饮孤独</span></span> <span>2019-12-11 11:25:08</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>I want my function to wait until the event <code>WebBrowser.DocumentCompleted</code> is completed. </p> <p>I am using <code>AutoResetEvent</code> and here is my code:</p> <pre><code>private static WebBrowser _browser = new WebBrowser(); private static AutoResetEvent _ar = new AutoResetEvent(false); private bool _returnValue = false; public Actions() //constructor { _browser.DocumentCompleted += PageLoaded; } public bool MyFunction() { _browser.Navigate("https://www.somesite.org/"); _ar.WaitOne(); // wait until receiving the signal, _ar.Set() return _returnValue; } private void PageLoaded(object sender, WebBrowserDocumentCompletedEventArgs e) { // do not enter more than once for each page if (e.Url.AbsolutePath != (sender as WebBrowser).Url.AbsolutePath) return; _returnValue = true; _ar.Set(); // send signal, unblock my function } </code></pre> <p>Here my problem is, PageLoaded never gets fired, and my function gets stuck on <code>_ar.WaitOne();</code>. How can I fix this issue ? perhaps there is another way to achieve this ?</p> <br /><h3>回答1:</h3><br /><p>Here is how you can synchronously get the page data of a website. This will help me build my web automation API. Special thanks to @Noseratio he helped me finding this perfect answer.</p> <pre><code>private static string _pageData = ""; public static void MyFunction(string url) { var th = new Thread(() =&gt; { var br = new WebBrowser(); br.DocumentCompleted += PageLoaded; br.Navigate(url); Application.Run(); }); th.SetApartmentState(ApartmentState.STA); th.Start(); while (th.IsAlive) { } MessageBox.Show(_pageData); } static void PageLoaded(object sender, WebBrowserDocumentCompletedEventArgs e) { var br = sender as WebBrowser; if (br.Url == e.Url) { _pageData = br.DocumentText; Application.ExitThread(); // Stops the thread } } } </code></pre> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/35400849/wait-for-webbrowser-documentcompleted-using-autoresetevent</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/c" hreflang="zh-hans">c#</a></div> <div class="field--item"><a href="/tag/events" hreflang="zh-hans">events</a></div> <div class="field--item"><a href="/tag/webbrowser-control" hreflang="zh-hans">webbrowser-control</a></div> <div class="field--item"><a href="/tag/autoresetevent" hreflang="zh-hans">autoresetevent</a></div> </div> </div> Wed, 11 Dec 2019 03:25:08 +0000 纵饮孤独 2252895 at https://www.e-learn.cn setEvent is called without ResetEvent https://www.e-learn.cn/topic/2176583 <span>setEvent is called without ResetEvent</span> <span><span lang="" about="/user/71" typeof="schema:Person" property="schema:name" datatype="">霸气de小男生</span></span> <span>2019-12-11 02:52:01</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>what happens if a manual-reset event is set using setEvent but not reset using ResetEvent; and that event is triggered multiple times.i.e. while the event is getting processed, again the event is set.</p> <p>following is the sample task:</p> <pre><code>void foo() { ... SetEvent(hEvent1); ... } void foo1() { ... SetEvent(hEvent2); ... } int MainHandler() { ... dwEvent = WaitForMultipleObjects(2, ghEvents, // array of objects FALSE, // wait for any object 5000); switch(dwEvent) { case hEvent1: //do something break; case hEvent2: //do something break; } } </code></pre> <p>Now, suppose while hEvent1's case is executing(i.e. it is still set), somehow again hEvent1 is triggered. I have deliberately not put ResetEvent(hEvent1) even though it is a manual-reset events. So, do we have a race condition?</p> <br /><h3>回答1:</h3><br /><p>In your example using <code>WaitForMultipleObjects</code>, you may have a potential problem if the events you are waiting on are not listed in increasing order of frequency in the array of event handles. Also note my comment that your code above assumes that <code>WaitForMultipleObjects</code> returns an event handle. It doesn't.</p> <p><code>WaitForMultipleObjects</code> will stop waiting when the <em>first</em> signaled event is seen, looking at the array from index zero upwards. </p> <p>So if you have an event that gets set (or does not get reset) as the first entry in the array, then the other events will get starved (i.e. will never be seen). </p> <p>So, in your example, as long as <code>hEvent1</code> is still signaled, <code>hEvent2</code> will not be seen.</p> <p>As an example of a common pattern, suppose we have some worker thread, whose thread function has been routed back to some owning class that contains the event objects and mutexes or whatever. The worker thread responds to just two events - a request to close tidily and a request to do some work. The code might look something like this:</p> <pre><code>UINT CMyClass::ThreadFunc() { // make an array of some interesting event handles HANDLE hEvents[2] = { m_hKillEvent, m_hWorkEvent }; // main loop - do work until killed while (true) { // wait for either event DWORD dwRet = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE); // see why we got signalled if (dwRet == WAIT_OBJECT_0) { // kill requested - exit loop break; } else if (dwRet == WAIT_OBJECT_0 + 1) { // work requested - do some work here } else { // error handling - bad handles? } } // normal exit return 0; } </code></pre> <p>As coded, this will work fine - the main thread calls <code>SetEvent(m_hWorkEvent)</code> to trigger the background thread to do some work and it calls <code>SetEvent(m_hKillEvent)</code> to make the worker thread close. Closing may be protected with some timeout in case the thread is mid-work, so something like:</p> <pre><code>// close worker thread SetEvent(m_hKillEvent); // wait for thread to die peacefully DWORD dwRet = WaitForSingleObject(m_hWorkerThread, 5000); if (dwRet == WAIT_TIMEOUT) { // worker failed to respond - error handling here } </code></pre> <p>Now, this closedown process will work fine, even if <code>m_hWorkEvent</code> is being signalled very frequently - for example, by the time <code>do some work here</code> has finished, the event has again been signalled. This is because <code>WaitForMultipleObjects</code> will always check the kill event <em>first</em> because it is the first one in the array.</p> <p>However, if the array had been defined like this:</p> <pre><code> // make an array of some interesting event handles HANDLE hEvents[2] = { m_hWorkEvent, m_hKillEvent }; </code></pre> <p>And if <code>m_hWorkEvent</code> is continually signalled (e.g. it gets set again during a long-running <code>do some work here</code>, or it is a manual reset event and you never reset it), then the thread will <em>never</em> exit cleanly because it will never see the kill signal. It will always try to do some work first.</p> <p>This is what I mean about ordering the events in the array in increasing order of frequency. The kill event has the lowest frequency (it is signaled only once), so it goes first. If you have three or more events for different work requests, you need to maintain the same ordering or some events will get starved.</p> <p>Whatever you decide to do, it's also worth noting that even if <code>WaitForMultipleObjects</code> got release on the "wrong" event, you can still check if a particular event is signaled by waiting with a zero timeout:</p> <pre><code>if (WaitForSingleObject(hSomeEvent, 0) == WAIT_OBJECT_0) { // ... hSomeEvent was signaled } </code></pre> <p>This can allow you to put intermediate checks for a kill event in suitable parts of a long-running background work procedure.</p> <br /><br /><br /><h3>回答2:</h3><br /><p>Events are like boolean flags - it's OK to assign true to it twice. No one can possibly be waiting on an event that's currently signaled, so nothing happens when you set it to signaled again.</p> <p>I'm not sure what you mean by "event is getting processed". It seems you use the word "event" twice with two different meanings - a kernel object represented by a <code>HANDLE</code>, and "something that my program has to do".</p> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/20985037/setevent-is-called-without-resetevent</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/windows" hreflang="zh-hans">windows</a></div> <div class="field--item"><a href="/tag/visual-c" hreflang="zh-hans">visual-c++</a></div> <div class="field--item"><a href="/tag/com" hreflang="zh-hans">com</a></div> <div class="field--item"><a href="/tag/autoresetevent" hreflang="zh-hans">autoresetevent</a></div> <div class="field--item"><a href="/tag/manualresetevent" hreflang="zh-hans">manualresetevent</a></div> </div> </div> Tue, 10 Dec 2019 18:52:01 +0000 霸气de小男生 2176583 at https://www.e-learn.cn C# Threading and events for pin pad device https://www.e-learn.cn/topic/2118955 <span>C# Threading and events for pin pad device</span> <span><span lang="" about="/user/237" typeof="schema:Person" property="schema:name" datatype="">北战南征</span></span> <span>2019-12-10 15:41:48</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>I am new in C# and currently working on the backend code to support PIN pad. Basically, my code </p> <pre><code>OpenDevice() -&gt; RequestPIN() -&gt; key in PIN on PIN PAD -&gt; GetResultPIN() -&gt; ConsolePrintOutPIN() -&gt; Print keyed PIN on the Console </code></pre> <p>I don't know how to write thread for this, so that once the "Enter key" is hit on the device after PIN, the system would automatically rolls to function <code>GetResultPIN()</code>. So, with my elementary knowledge, I wrote the following codes using <code>Console.ReadLine()</code> to separate each procedure:</p> <pre><code> static void Main(string[] args) { // 1. Open PIN Pad device OpenDevice(); Console.ReadLine();// to hold up from the previous procedure, it is *not* for input data purpose // 2. Request PIN from PIN Pad device. // On the PIN Pad device, it reads: // "Key in the PIN: " RequestPIN(); Console.ReadLine();// to hold up from the previous procedure, it is *not* for input data purpose // 3. get PIN from the device GetResultPIN(); // 4. Print out on the Console ConsolePrintOutPIN(); Console.ReadLine();// to hold up from the previous procedure, it is *not* for input data purpose } </code></pre> <p><strong><em>Question:</em> Can anyone give me any suggestions on how to use threading/event/delegate that can avoid using <code>Console.ReadLine()</code>?</strong></p> <p>As commended above, <code>Console.ReadLine()</code> is used just to stop the procedure (sorry about my naivety of using it this way....) Once I use <code>Console.ReadLine()</code>, between <code>RequestPIN()</code> and <code>GetResult()</code>, the system would at least wait for me to Key in the PIN from the PIN PAD (connected to the computer through USB, <strong>not</strong> from key board), and then I would hit any key on the keyboard to pass <code>Console.ReadLine()</code> and <code>GetResultPIN()</code> would be able to get my PIN number from PIN Pad.....the whole program works now, it is not customer ready, because it is very choppy, doesn't flow due to <code>Console.ReadLine()</code> I added.....</p> <p>So ideally, all the method would flow together. Once the device is opened, <code>RequestPIN()</code> should show on the PIN Pad screen asking for PIN number, some one can key in and hit enter on PIN Pad and it naturally flow to <code>GetResultPIN()</code> and read the result, and then it prints the PIN on the console...`</p> <p>or</p> <p>if the person doesn't key in PIN, the device would wait for 30s and directly goes to <code>GetResultPIN()</code> and print out "0000" on the Console</p> <p>I have looked up treading and delegate, but am not sure how to use them in this situation.... Thank you!</p> <p><strong><em>Reference:</em></strong> RequestPin() and GetResultPIN are listed down below:</p> <pre><code>mIPAD.requestPIN(waitTime, pinMsg, minLen, maxLen, tone, option, ","); //This function wraps device command 0x04. //It directs the device to prompt the user to enter a PIN //by displaying one of five predetermined messages and playing // a specified sound. //The messages on the device’s screen look like the figures below. //The event associated with this function is //OnPINRequestCompleteEvent. </code></pre> <p><em>waitTime: Time the device should wait for the user to begin PIN entry</em></p> <p><em>pinMsg: Message to display as a user prompt, such as "Enter PIN", "ReEnter PIN", "Verify PIN", etc</em></p> <p><em>minLen and maxLen: minimum length and maximum length of PIN</em></p> <p><em>tone: beeping tone option</em></p> <p><em>Option: Verify PIN, not Verify PIN, ISO0 FOrmat, ISO3 Format</em></p> <p><em>Output would be: an integer, 0: Success, Non-Zero: Error</em></p> <pre><code> public void GetResultPIN() { StringBuilder sb = new StringBuilder(); sb.Append(mIPAD.pin.KSN); // Key Serial Number: //a given number from the device, unique for each device sb.Append("," + mIPAD.pin.EPB); // EPB: encryption of PIN after Dubpt TripleDES, // essentially, EPB is PIN sb.Append("," + mIPAD.getStatusCode()); //status code: Zero is good/done // None-Zero is Error sb.Append("\r\n"); result = sb.ToString(); } </code></pre> <p><em>Basically, the GetResultPIN() returns a string of random code, for example: <code>9A00030000047A2000AB,AD781711481B08A2,0</code> when PIN is successful. If the pin-input part is skipped, it would return <code>,,0</code>.</em></p> <br /><h3>回答1:</h3><br /><p>Really hard to know if this will work or not without hardware to play with...</p> <p>This is the way I envisioned it working:</p> <pre><code> static void Main() { OpenDevice(); RequestPIN(); if (GetResultPIN()) { // do something with the PIN: var pin = mIPAD.pin.EPB; // ... } else { Console.WriteLine("0000"); } } public static bool GetResultPIN() { TimeSpan timeout = TimeSpan.FromSeconds(30); System.Diagnostics.Stopwatch SW = new System.Diagnostics.Stopwatch(); SW.Start(); while (mIPAD.getStatusCode() != 0 &amp;&amp; SW.Elapsed &lt; timeout) { System.Threading.Thread.Sleep(50); // small call to prevent CPU usage ramping to 100% } return (mIPAD.getStatusCode() == 0); } </code></pre> <br /><br /><br /><h3>回答2:</h3><br /><p>You can rewrite your api to:</p> <ul><li>make <code>GetResultPIN()</code> return a value</li> <li>use this value as input for <code>ConsolePrintOutPIN()</code></li> </ul><p>In <code>GetResultPIN</code> you need to make a Task To ReadYour Pin and wait for it.</p> <p>See : https://msdn.microsoft.com/en-us/library/dd537610(v=vs.110).aspx</p> <p>You can do something like this:</p> <pre><code>public string GetResultPIN() { StringBuilder sb = new StringBuilder(); sb.Append(mIPAD.pin.KSN); // Key Serial Number: //a given number from the device, unique for each device sb.Append("," + mIPAD.pin.EPB); // EPB: encryption of PIN after Dubpt TripleDES, // essentially, EPB is PIN sb.Append("," + mIPAD.getStatusCode()); //status code: Zero is good/done // None-Zero is Error sb.Append("\r\n"); Thread.Sleep(20*1000); // it is in milliseconds return sb.ToString(); } </code></pre> <br /><br /><br /><h3>回答3:</h3><br /><p>Thanks for posting... The solution is still not ideal.... I also did some more testing regarding the function <code>RequestPIN()</code>. I have the following four scenarios:</p> <ol><li>User finishes keying in PIN sooner than the <code>waitTime</code> goes out. <code> onPINRequestComplete : OpStatus:0 KSN:9A00030000047A2000C8 EPB:39DED176D3EA40B9 .............................. </code></li> <li><p>User doesn't finish keying in PIN when the <code>waitTime</code> is going out.<br /><code> onPINRequestComplete : OpStatus:2 KSN:00000000000000000000 EPB:0000000000000000 .............................. </code></p></li> <li><p>User cancels the PIN pad option by pressing "Cancel X" key on the PIN Pad.</p> <p><code> onPINRequestComplete : OpStatus:1 KSN:00000000000000000000 EPB:0000000000000000 .............................. </code></p></li> <li><p>User doesn't key in PIN at all during the waitTime, and then waitTime goes out.</p> <p><code> onPINRequestComplete : OpStatus:2 KSN:00000000000000000000 EPB:0000000000000000 .............................. </code> So, scenario 1 and 3 would require the thread to wake up right away, while 2 and 4 would require the thread to wake up when the waiTime goes out. So using <code>Thread.sleep(20*1000)</code> within <code>GetResultPIN()</code> would work perfectly for scenario 2 and 4. As for 1 and 3, the user has to wait for a long time.... </p></li> </ol><p>On the other hand, I found some code about <code>Event</code></p> <p>Within <strong>Car.cs</strong>:</p> <pre><code>using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace WaitOnTasksToComplete { class Car { public event Action OnChange; private double speed; public double Speed { get { return speed; } set { speed = value; if (speed &gt;= 60) { if (OnChange != null) { OnChange(); } } } } } } </code></pre> <p>Within <strong>Program.cs</strong>:</p> <pre><code>using System; namespace WaitOnTasksToComplete { class Program { static void Main(string[] args) { Car c = new Car(); c.OnChange += C_OnChange; c.Speed = 5; c.Speed = 55; c.Speed = 65; c.Speed = 75; } private static void C_OnChange() { Console.WriteLine("Event fired: Car goes higher than 60 MPH."); } } } </code></pre> <p>So, basically once the <code>Car.speed</code> jumps above 60, the alarm would show. I am considering borrowing the condition into my situation: Initialize <code>OpStatus = -999</code>. When <code>OpStatus=0 or 1</code>, keep executing <code>GetResultPIN()</code> and <code>PrintMessagePIN()</code>. If <code>OpStatus=2 or others</code>, keep waiting...</p> <p>That is just my thoughts.... still have no clue how to implement it.... Any related ideas or suggestions would be appreciated..... </p> <br /><br /><br /><h3>回答4:</h3><br /><p>Ah, I figured out. I am basically using threading here. The main flow is <code>OpenDevice()-&gt;RequestPIN()-&gt;Thread(()=&gt;CheckOpStatus(getResultPIN)) -&gt; Thread.Start()</code>. Within the Thread, a loop is set to check every half second what the <code>OpStatus</code> is. Per my previous post, <code>OpStatus</code>is the output parameter of PIN Pad, <code>zero- success; non-zero: failure</code>. That said, the loop would proceed until either <code>bool condition_WithinWaitTime</code> or <code>bool condition_NoKeyEvent</code> breaks. After breaking out, invoke the <code>getResultPIN</code> and so on....</p> <p>Here is my source code, as PIN input is one of my functions, the rest of which have very similar behavior in terms programming (request-&gt;manual operation-&gt;feedback), so I also included a delegate variable to represents all functions (card swiping, PIN, signature bla bla). </p> <pre><code> static void Main(string[] args) { OpenDevice(); EventGetPIN(); } static void EventGetPIN() { myDel getResult = new myDel(GetResultPIN); Thread thread1 = new Thread(() =&gt; CheckOpStatus(getResult)); myDel requestDel = new myDel(RequestPIN); requestDel(); thread1.Start(); } static void CheckOpStatus(Delegate getResult) { int count = 0; int checkingPeriod = 500; int totalWaitTime = waitTime * 1000 + offsetTime; string OpStatus; string ksnStart = mIPAD.getKSN(); string ksn = ksnStart; bool condition_WithinWaitTime = true; bool condition_NoKeyEvent = true; while (condition_WithinWaitTime &amp; condition_NoKeyEvent) { count++; OpStatus = mIPAD.getStatusCode().ToString(); ksn = mIPAD.getKSN(); //Console.WriteLine(OpStatus); condition_WithinWaitTime = (count * checkingPeriod) &lt; totalWaitTime; condition_NoKeyEvent = (ksn == ksnStart); Thread.Sleep(checkingPeriod); } getResult.DynamicInvoke(); } </code></pre> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/31662622/c-sharp-threading-and-events-for-pin-pad-device</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/c" hreflang="zh-hans">c#</a></div> <div class="field--item"><a href="/tag/callback" hreflang="zh-hans">callback</a></div> <div class="field--item"><a href="/tag/delegates" hreflang="zh-hans">delegates</a></div> <div class="field--item"><a href="/tag/event-handling" hreflang="zh-hans">event-handling</a></div> <div class="field--item"><a href="/tag/autoresetevent" hreflang="zh-hans">autoresetevent</a></div> </div> </div> Tue, 10 Dec 2019 07:41:48 +0000 北战南征 2118955 at https://www.e-learn.cn Queues And Wait Handles in C# https://www.e-learn.cn/topic/2114355 <span>Queues And Wait Handles in C#</span> <span><span lang="" about="/user/172" typeof="schema:Person" property="schema:name" datatype="">无人久伴</span></span> <span>2019-12-10 14:55:56</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>I've had the following code in my application for some years and have never seen an issue from it.</p> <pre><code>while ((PendingOrders.Count &gt; 0) || (WaitHandle.WaitAny(CommandEventArr) != 1)) { lock (PendingOrders) { if (PendingOrders.Count &gt; 0) { fbo = PendingOrders.Dequeue(); } else { fbo = null; } } // Do Some Work if fbo is != null } </code></pre> <p>Where CommandEventArr is made up of the NewOrderEvent (an auto reset event) and the ExitEvent (a manual reset event).</p> <p>But I'm not sure if this is thread safe (assuming N producer threads that all lock the queue before enqueing and one consumer thread that runs the code above). Also, we can assume that the Queue.Count property just returns one instance Int32 value from the Queue class (without volatile or interlocked or a lock, etc.).</p> <p>What's the usual pattern used with a Queue and an AutoResetEvent to fix this and do what I'm trying to do with the code above?</p> <p>(Edited to change the question slightly after it was correctly pointed out that Queue.Count could do anything and its implementation specific).</p> <br /><h3>回答1:</h3><br /><p>Looks quite thread-safe to me, the WaitAny() will simply complete immediately because thee event is already set. That's <em>not</em> a problem.</p> <p>Don't break threading sync that works. But if you want a better mousetrap then you could consider Joe Duffy's BlockingQueue in this magazine article. A more general version of it is available in .NET 4.0, System.Collections.Concurrent.BlockingCollection with ConcurrentQueue as a practical implementation of it.</p> <br /><br /><br /><h3>回答2:</h3><br /><p>You are correct. The code is not thread-safe. But not for the reason you think. </p> <p>The AutoResetEvent is fine. Though, only because you acquire a lock and retest PendingOrders.Count. The real crux of the matter is that you are calling PendingOrders.Count outside of a lock. Because the Queue class is not thread-safe your code is not thread-safe... period.</p> <p>Now in reality you will probably never have a problem with this for two reasons. First, Queue.Count property is almost certainly designed to never leave the object in a half-baked state. After all, it will probably just return an instance variable. Second, the lack of a memory barrier on that read will not have a significant impact in the broader context of your code. The worst thing that will happen is that you will get a stale read on one iteration of the loop and then the acquired lock will implicitly create a memory barrier and a fresh read will take place on the next iteration. I am assuming here that there is only one thread queueing items. Things change considerably if there are 2 or more.</p> <p>However, let me make this perfectly clear. <strong>You have no guarantee that PendingOrders.Count will not alter the state of the object during its execution</strong>. And because it is not wrapped in a lock, another thread could initiate an operation on it while is still in that half-backed state.</p> <br /><br /><br /><h3>回答3:</h3><br /><p>Using manual events...</p> <pre><code>ManualResetEvent[] CommandEventArr = new ManualResetEvent[] { NewOrderEvent, ExitEvent }; while ((WaitHandle.WaitAny(CommandEventArr) != 1)) { lock (PendingOrders) { if (PendingOrders.Count &gt; 0) { fbo = PendingOrders.Dequeue(); } else { fbo = null; NewOrderEvent.Reset(); } } } </code></pre> <p>Then you need to ensure a lock on the enqueue side as well:</p> <pre><code> lock (PendingOrders) { PendingOrders.Enqueue(obj); NewOrderEvent.Set(); } </code></pre> <br /><br /><br /><h3>回答4:</h3><br /><p>You should only use the WaitAny for that, and ensure that it gets signaled on every new order added to the PendingOrders collection:</p> <pre><code>while (WaitHandle.WaitAny(CommandEventArr) != 1)) { lock (PendingOrders) { if (PendingOrders.Count &gt; 0) { fbo = PendingOrders.Dequeue(); } else { fbo = null; //Only if you want to exit when there are no more PendingOrders return; } } // Do Some Work if fbo is != null } </code></pre> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/2741042/queues-and-wait-handles-in-c-sharp</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/c" hreflang="zh-hans">c#</a></div> <div class="field--item"><a href="/tag/net" hreflang="zh-hans">.net</a></div> <div class="field--item"><a href="/tag/multithreading" hreflang="zh-hans">multithreading</a></div> <div class="field--item"><a href="/tag/queue" hreflang="zh-hans">queue</a></div> <div class="field--item"><a href="/tag/autoresetevent" hreflang="zh-hans">autoresetevent</a></div> </div> </div> Tue, 10 Dec 2019 06:55:56 +0000 无人久伴 2114355 at https://www.e-learn.cn