Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>You need some mechanism to make a "queue control", coordinating steps according to the order you want them occurring.</p> <p>Recently I have needed to implement something like this to force a specific order in the execution of several threads in a unit test.</p> <p>Here is my suggestion:</p> <p><strong>QueueSynchronizer:</strong></p> <pre><code>/// &lt;summary&gt; /// Synchronizes steps between threads. /// &lt;/summary&gt; public class QueueSynchronizer { /// &lt;summary&gt; /// Constructor. /// &lt;/summary&gt; /// &lt;param name="minWait"&gt;Minimum waiting time until the next try.&lt;/param&gt; /// &lt;param name="maxWait"&gt;Maximum waiting time until the next try.&lt;/param&gt; public QueueSynchronizer(Int32 minWait, Int32 maxWait) { } private Mutex mx = new Mutex(); /// &lt;summary&gt; /// Minimum waiting time until the next try. /// &lt;/summary&gt; private Int32 minWait = 5; /// &lt;summary&gt; /// Maximum waiting time until the next try. /// &lt;/summary&gt; private Int32 maxWait = 500; int currentStep = 1; /// &lt;summary&gt; /// Key: order in the queue; Value: Time to wait. /// &lt;/summary&gt; private Dictionary&lt;int, int&gt; waitingTimeForNextMap = new Dictionary&lt;int, int&gt;(); /// &lt;summary&gt; /// Synchronizes by the order in the queue. It starts from 1. If is not /// its turn, the thread waits for a moment, after that, it tries again, /// and so on until its turn. /// &lt;/summary&gt; /// &lt;param name="orderInTheQueue"&gt;Order in the queue. It starts from 1.&lt;/param&gt; /// &lt;returns&gt;The &lt;see cref="Mutex"/&gt;The mutex that must be released at the end of turn. /// &lt;/returns&gt; public Mutex Sincronize(int orderInTheQueue) { do { //while it is not the turn, the thread will stay in this loop and sleeping for 100, 200, ... 1000 ms if (orderInTheQueue != this.currentStep) { //The next in queue will be waiting here (other threads). mx.WaitOne(); mx.ReleaseMutex(); //Prevents 100% processing while the current step does not happen if (!waitingTimeForNextMap.ContainsKey(orderInTheQueue)) { waitingTimeForNextMap[orderInTheQueue] = this.minWait; } Thread.Sleep(waitingTimeForNextMap[orderInTheQueue]); waitingTimeForNextMap[orderInTheQueue] = Math.Min(waitingTimeForNextMap[orderInTheQueue] * 2, this.maxWait); } } while (orderInTheQueue != this.currentStep); mx.WaitOne(); currentStep++; return mx; } } </code></pre> <p><code>Start()</code> and <code>Close()</code> with <code>QueueSynchronizer</code>: </p> <pre><code>//synchronizer private static QueueSynchronizer queueSynchronizer; private static Thread instanceCaller; private static WaitForm instance; private static AutoResetEvent waitFormStarted = new AutoResetEvent(false); private static object locker = new object(); /// &lt;summary&gt; /// Initializes WaitForm to start a single task /// &lt;/summary&gt; /// &lt;param name="header"&gt;WaitForm header&lt;/param&gt; /// &lt;param name="message"&gt;Message displayed&lt;/param&gt; /// &lt;param name="showProgressBar"&gt;True if we want a progress bar, else false&lt;/param&gt; public static void Start(string header, string message, bool showProgressBar) { queueSynchronizer = new QueueSynchronizer(); InitializeCallerThread(showProgressBar, header, message); instanceCaller.Start(); } /// &lt;summary&gt; /// Initializes caller thread for executing a single command /// &lt;/summary&gt; /// &lt;param name="showProgressBar"&gt;&lt;/param&gt; /// &lt;param name="header"&gt;&lt;/param&gt; /// &lt;param name="message"&gt;&lt;/param&gt; private static void InitializeCallerThread(bool showProgressBar, string header, string message) { waitFormStarted.Reset(); instanceCaller = new Thread(() =&gt; { lock (locker) { //Queuing to run on first. Mutex mx = queueSynchronizer.Sincronize(1); try { instance = new WaitForm() { Header = header, Message = message, IsProgressBarVisible = showProgressBar }; } finally { //I think is here that ends the first step!? mx.ReleaseMutex(); } waitFormStarted.Set(); } instance.ShowDialog(); }); instanceCaller.Name = "WaitForm thread"; instanceCaller.SetApartmentState(ApartmentState.STA); instanceCaller.IsBackground = true; } /// &lt;summary&gt; /// Closes current form /// &lt;/summary&gt; public static void Close() { //Queuing to run on second. Mutex mx = queueSynchronizer.Sincronize(2); try { lock (locker) { if (instance != null &amp;&amp; !instance.IsClosed) { waitFormStarted.WaitOne(); instance.FinalizeWork(); instance.Dispatcher.Invoke( new Action(() =&gt; { instance.Close(); })); } } } finally { mx.ReleaseMutex(); } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload