Ensuring execution order between multiple threads - c#

I am having a kinda annoying problem mostly due to my low skill level/experience in C# multithreading.
Here is the background. In my framework, I have a static class named WaitFormHelper, which has two static methods (well... actually more but we don't care here), Start() and Close()
The Start() method initializes and starts a thread which will acquire a lock on the locker object and create a WaitForm (which is a small loading control with a custom message and a progress bar)
In my current project, I have a method which starts a WaitForm, performs calculations, then closes the WaitForm. Nothing fancy at all.
The method looks like the following, I simplified it as much as possible:
public void PerformCalculations()
{
try
{
WaitFormHelper.Start("Title", "message", false);
if (this.CalculationsParameters.IsInvalid)
{
return;
}
// Perform all those lengthy calculations here
}
// catch whatever exception I may have to catch, we don't care here
finally
{
WaitFormHelper.Close();
}
}
Here are the Start() and Close() methods with related methods & attributes, simplified as well:
private static Thread instanceCaller;
private static WaitForm instance;
private static AutoResetEvent waitFormStarted = new AutoResetEvent(false);
private static object locker = new object();
/// <summary>
/// Initializes WaitForm to start a single task
/// </summary>
/// <param name="header">WaitForm header</param>
/// <param name="message">Message displayed</param>
/// <param name="showProgressBar">True if we want a progress bar, else false</param>
public static void Start(string header, string message, bool showProgressBar)
{
InitializeCallerThread(showProgressBar, header, message);
instanceCaller.Start();
}
/// <summary>
/// Initializes caller thread for executing a single command
/// </summary>
/// <param name="showProgressBar"></param>
/// <param name="header"></param>
/// <param name="message"></param>
private static void InitializeCallerThread(bool showProgressBar, string header, string message)
{
waitFormStarted.Reset();
instanceCaller = new Thread(() =>
{
lock (locker)
{
instance = new WaitForm()
{
Header = header,
Message = message,
IsProgressBarVisible = showProgressBar
};
waitFormStarted.Set();
}
instance.ShowDialog();
});
instanceCaller.Name = "WaitForm thread";
instanceCaller.SetApartmentState(ApartmentState.STA);
instanceCaller.IsBackground = true;
}
/// <summary>
/// Closes current form
/// </summary>
public static void Close()
{
lock (locker)
{
if (instance != null && !instance.IsClosed)
{
waitFormStarted.WaitOne();
instance.FinalizeWork();
instance.Dispatcher.Invoke(
new Action(() =>
{
instance.Close();
}));
}
}
}
Now let's get to the problem
This usually works fine, except in this case:
If this.CalculationsParameters.IsInvalid is true (ie. as you probably already understood, I can't perform calculations for some reason, such as "user entering crap in my forms"), the execution directly closes my WaitForm.
However in this case, the main thread will reach the Close method and acquire a lock on the locker object before the thread fired by the Start() method.
What happens is that: Close acquires lock, tries to close the form but instance is still null because the Thread created in InitializeCallerThread is still waiting for the lock to actually create it. Close releases lock, InitializeCallerThread acquires it and... shows a WaitForm which will not close.
Now I know that I can simply fix this problem by testing if the calculation parameters are invalid before actually starting the WaitForm, but well, problem is this WaitForm is supposed to be used by all applications of our framework (which includes 40+ different apps used and maintained in 4 countries), so ideally I'd rather prefer seeing my WaitForm working at all cases.
Do you have any idea on how could I synchronize this to make sure the starter thread is definitely called and executed first?
As you can see I already use an AutoResetEvent for this matter, but if I listen to it before the test if (instance != null) I will end up stuck in my case.
Hope this is clear enough! Thank you!

You need some mechanism to make a "queue control", coordinating steps according to the order you want them occurring.
Recently I have needed to implement something like this to force a specific order in the execution of several threads in a unit test.
Here is my suggestion:
QueueSynchronizer:
/// <summary>
/// Synchronizes steps between threads.
/// </summary>
public class QueueSynchronizer
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="minWait">Minimum waiting time until the next try.</param>
/// <param name="maxWait">Maximum waiting time until the next try.</param>
public QueueSynchronizer(Int32 minWait, Int32 maxWait)
{
}
private Mutex mx = new Mutex();
/// <summary>
/// Minimum waiting time until the next try.
/// </summary>
private Int32 minWait = 5;
/// <summary>
/// Maximum waiting time until the next try.
/// </summary>
private Int32 maxWait = 500;
int currentStep = 1;
/// <summary>
/// Key: order in the queue; Value: Time to wait.
/// </summary>
private Dictionary<int, int> waitingTimeForNextMap = new Dictionary<int, int>();
/// <summary>
/// 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.
/// </summary>
/// <param name="orderInTheQueue">Order in the queue. It starts from 1.</param>
/// <returns>The <see cref="Mutex"/>The mutex that must be released at the end of turn.
/// </returns>
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;
}
}
Start() and Close() with QueueSynchronizer:
//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();
/// <summary>
/// Initializes WaitForm to start a single task
/// </summary>
/// <param name="header">WaitForm header</param>
/// <param name="message">Message displayed</param>
/// <param name="showProgressBar">True if we want a progress bar, else false</param>
public static void Start(string header, string message, bool showProgressBar)
{
queueSynchronizer = new QueueSynchronizer();
InitializeCallerThread(showProgressBar, header, message);
instanceCaller.Start();
}
/// <summary>
/// Initializes caller thread for executing a single command
/// </summary>
/// <param name="showProgressBar"></param>
/// <param name="header"></param>
/// <param name="message"></param>
private static void InitializeCallerThread(bool showProgressBar, string header, string message)
{
waitFormStarted.Reset();
instanceCaller = new Thread(() =>
{
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;
}
/// <summary>
/// Closes current form
/// </summary>
public static void Close()
{
//Queuing to run on second.
Mutex mx = queueSynchronizer.Sincronize(2);
try
{
lock (locker)
{
if (instance != null && !instance.IsClosed)
{
waitFormStarted.WaitOne();
instance.FinalizeWork();
instance.Dispatcher.Invoke(
new Action(() =>
{
instance.Close();
}));
}
}
}
finally
{
mx.ReleaseMutex();
}
}

You need to Join on the thread that you created. By joining on a thread you'll block at that point until the thread has finished executing.
public static void Close()
{
lock (locker)
{
instanceCaller.Join();
if (instance != null && !instance.IsClosed)
{
waitFormStarted.WaitOne();
instance.FinalizeWork();
instance.Dispatcher.Invoke(
new Action(() =>
{
instance.Close();
}));
}
}
}

Related

Progress bar on separate thread not updating

In my project i have a Form, like a Task Dialog, that displays on its own thread... This way when the main thread locks up, the Task Dialog's ProgressBar and status can still be updated.
The issue im having is that the ProgressBar is not updating. The status text updates, but the ProgressBar doesn't move until right before the Form closes. The Form is being opened in the main thread. Here is my code:
public partial class TaskForm : Form
{
/// <summary>
/// Gets or Sets whether the task is cancelable
/// </summary>
protected bool Cancelable = true;
/// <summary>
/// Returns whether the Task form is already open and running
/// </summary>
/// <returns></returns>
public static bool IsOpen
{
get { return (Instance != null && !Instance.IsDisposed); }
}
/// <summary>
/// The task dialog's instance
/// </summary>
private static TaskForm Instance;
/// <summary>
/// Private constructor... Use the Show() method rather
/// </summary>
private TaskForm()
{
InitializeComponent();
}
/// <summary>
/// Open and displays the task form.
/// </summary>
/// <param name="Parent">The calling form, so the task form can be centered</param>
public static void Show(Form Parent, string WindowTitle, string InstructionText, string SubMessage, bool Cancelable, ProgressBarStyle Style)
{
// Make sure we dont have an already active form
if (Instance != null && !Instance.IsDisposed)
throw new Exception("Task Form is already being displayed!");
// Create new instance
Instance = new TaskForm();
Instance.Text = WindowTitle;
Instance.labelInstructionText.Text = InstructionText;
Instance.labelContent.Text = SubMessage;
Instance.Cancelable = Cancelable;
Instance.progressBar.Style = Style;
// Hide Cancel
if (!Cancelable)
{
Instance.panelButton.Hide();
Instance.Padding = new Padding(0, 0, 0, 15);
Instance.BackColor = Color.White;
}
// Set window position to center parent
double H = Parent.Location.Y + (Parent.Height / 2) - (Instance.Height / 2);
double W = Parent.Location.X + (Parent.Width / 2) - (Instance.Width / 2);
Instance.Location = new Point((int)Math.Round(W, 0), (int)Math.Round(H, 0));
// Run form in a new thread
Thread thread = new Thread(new ThreadStart(ShowForm));
thread.IsBackground = true;
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
Thread.Sleep(100); // Wait for Run to work
}
/// <summary>
/// Closes the Task dialog
/// </summary>
public static void CloseForm()
{
if (Instance == null || Instance.IsDisposed)
throw new Exception("Invalid Operation. Please use the Show method before calling any operational methods");
Instance.Invoke((Action)delegate()
{
Instance.Close();
});
}
/// <summary>
/// Runs the form in a new application, to prevent thread lock
/// </summary>
protected static void ShowForm()
{
Application.Run(Instance);
}
/// <summary>
/// Updates the instruction text on the task dialog
/// </summary>
/// <param name="Message"></param>
public static void UpdateInstructionText(string Message)
{
if (Instance == null || Instance.IsDisposed)
throw new Exception("Invalid Operation. Please use the Show method before calling any operational methods");
Instance.Invoke((Action)delegate()
{
Instance.labelInstructionText.Text = Message;
});
}
/// <summary>
/// Updates the detail text above the progress bar
/// </summary>
/// <param name="Message"></param>
public static void UpdateStatus(string Message)
{
if (Instance == null || Instance.IsDisposed)
throw new Exception("Invalid Operation. Please use the Show method before calling any operational methods");
Instance.Invoke((Action)delegate()
{
Instance.labelContent.Text = Message;
});
}
/// <summary>
/// Updates the progress bar's value
/// </summary>
/// <param name="Percent"></param>
public static void UpdateProgress(int Percent)
{
if (Instance == null || Instance.IsDisposed)
throw new Exception("Invalid Operation. Please use the Show method before calling any operational methods");
Instance.Invoke((Action)delegate()
{
Instance.progressBar.Step = Percent;
Instance.progressBar.PerformStep();
Instance.progressBar.Refresh();
});
}
#region Non Static
private void CancelBtn_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.Cancel;
this.Close();
}
#endregion
}
It doesnt make sense that text updates when i call the UpdateStatus and UpdateInstructionText methods, but the ProgressBar does not update when calling UpdateProgress. Any help will be appreciated.
by looking at your code, you are passing the percentage in UpdateProgress() method in the progressBar.Step property, which the step indicate the amount to increase when PerformStep() is called.
since the UpdateProgress() method is used in percentage, i would put
Instance.progressBar.Step = Percent;
into static Show() method
...
Instance.progressBar.Style = Style;
Instance.progressBar.Step = Percent;
...
and you can see the it updating the progress bar precentage.
I'm using below example
TaskForm.Show(this, "Task is executing...", "Step 1 - Preparing...",
"Runninig", true, ProgressBarStyle.Continuous);
for (int i = 1; i <= 100; i++)
{
TaskForm.UpdateInstructionText("Step 1 - Executing..." + i );
TaskForm.UpdateStatus("Running " + i);
TaskForm.UpdateProgress(i);
Thread.Sleep(1000);
}

C# While Loop in Worker Thread for listening command and response

Overview of the problem:
I try to use a thread (while..loop) to listen a command from user. If user send a command, it will assign new value in the global variable which is in the class (LoopingWorkerThread).
I don't understand if I don't put the thread sleep value lower than 10 milliseconds, and I wouldn't get any response (it is in the ListenCommand method) . Look like the global parameter is being overwritten "_CommandReceived" in the method, probably the processor run to fast and ignore the value of the parameter had changed ("_CommandReceived").
Kindly comment if there is any better mechanism. I had lock it in the ListenCommand while loop.
The following are the codes:
public class LoopingWorkerThread
{
/// <summary>
/// Local main thread for LoopingWorkerThread
/// </summary>
private Thread t;
/// <summary>
/// Local parameter to identify the LoopingWorkerThread Is On
/// </summary>
private bool _IsOn;
/// <summary>
/// Local parameter to store command received from user
/// </summary>
private int _CommandReceived;
/// <summary>
/// Local object to use for locking the LoopingWorker Thread
/// </summary>
private object _LockListenCommand = new object();
/// <summary>
/// Properties of LoopingWorker Thread Is On
/// </summary>
public bool IsOn
{
get { return _IsOn; }
set { _IsOn = value; }
}
/// <summary>
/// Property of storing the command received from user
/// </summary>
public int CommandReceived
{
get { return _CommandReceived; }
set { _CommandReceived = value; }
}
/// <summary>
/// Delegate for OnResponse Event Handler
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public delegate void OnResponseHandler(object sender, ResponseArg e);
/// <summary>
/// Event of OnResponse
/// </summary>
public event OnResponseHandler OnResponse;
/// <summary>
/// Constructor of LoopingWorkerThread Class
/// </summary>
public LoopingWorkerThread()
{
_IsOn = false;
}
/// <summary>
/// Method of LoopingWorkerThread Function
/// </summary>
private void ListenCommand()
{
lock (_LockListenCommand)
while (_IsOn)
{
switch (_CommandReceived)
{
case 0:
// Ignore default command
break;
case 1:
FireOnResponse("Received cmd 1, response [Hello One]");
break;
case 2:
FireOnResponse("Received cmd 2, response [Hello Two]");
break;
default:
FireOnResponse("Error. Received unidentified command - " + _CommandReceived.ToString());
break;
}
//Console.WriteLine("ThreadProc: Cmd:[{0}] - Response:{1}", _CommandReceived.ToString(), ReaderResponse);
// Reset or Clear the Command Received
_CommandReceived = 0;
// If the sleep less than 10 millisecond, it always don't catch the
// command received which assigned to 1 or 2. Don't understand, or is there
// any better method.
**Thread.Sleep(10);**
}
}
/// <summary>
/// Function of firing response event back to user
/// </summary>
/// <param name="message"></param>
private void FireOnResponse(string message)
{
ResponseArg myarg = new ResponseArg(message);
if (OnResponse != null)
OnResponse(this, myarg);
}
/// <summary>
/// Method of starting the LoopingWorkerThread
/// </summary>
public void Start()
{
_IsOn = true;
FireOnResponse("Main thread: Started.");
// The constructor for the Thread class requires a ThreadStart
// delegate that represents the method to be executed on the
// thread. C# simplifies the creation of this delegate.
t = new Thread(new ThreadStart(ListenCommand));
// Start ThreadProc. Note that on a uniprocessor, the new
// thread does not get any processor time until the main thread
// is preempted or yields. Uncomment the Thread.Sleep that
// follows t.Start() to see the difference.
t.Start();
//Thread.Sleep(0);
FireOnResponse("Main thread: Call Start().");
}
/// <summary>
/// Method of stopping the LoopingWorkerThread
/// </summary>
public void Stop()
{
_IsOn = false;
t.Join();
//t.Abort();
FireOnResponse("LoopingWorker Thread is stopped.");
}
/// <summary>
/// Method of sending command to the LoopingWorkerThread
/// </summary>
/// <param name="readercmd"></param>
public void SendCommand(int readercmd)
{
_CommandReceived = readercmd;
}
}
Your code works because Thread.Sleep produces the necessary memory barrier required to read _commandReceived correctly. If you remove the Thread.Sleep call then you also remove the implicit memory barrier. Obviously, this is not a good mechanism to rely on though.
More importantly you are going about this the wrong way. What you should be using is the producer-consumer pattern. This is pretty easy with the BlockingCollection class since it blocks the consumer on Take while the queue is empty.
public class Example
{
private BlockingCollection<int> commands = new BlockingCollection<int>();
public Example()
{
var thread = new Thread(Run);
thread.IsBackground = true;
thread.Start();
}
public void SendCommmand(int command)
{
commands.Add(command);
}
private void Run()
{
while (true)
{
int command = commands.Take();
ProcessCommand(command);
}
}
private void ProcessCommand(int command)
{
// Process the command here.
}
}
BlockingCollection is available for 3.5 as part of the Reactive Extensions download.
Try declaring the variable volatile. More about this on http://msdn.microsoft.com/en-us/library/x13ttww7.aspx

Using AutoResetEvent to signal worker thread

I have a service that is running constantly processing data, it receives requests to process new data through messaging. While it's busy processing new requests get merged together so that they are then all processed at once. An AutoResetEvent is used to notify the processor that a new request is available.
My question is in EventLoop should it be possible that currentRequest after the WaitOne to be null?
Is it bad practice to have the _eventAvailable.Set() outside of the lock(_eventLocker)? I moved it out so that it wouldn't start going at the WaitOne and immediately contest the lock(_eventLocker).
Any suggestions on how to better write the following code?
public sealed class RealtimeRunner : MarshalByRefObject
{
/// <summary>
/// The actual event, new events get merged into this if it is not null
/// </summary>
private Request _pendingRequest;
/// <summary>
/// Used to signal the runner thread when an event is available to process
/// </summary>
private readonly AutoResetEvent _eventAvailable = new AutoResetEvent(false);
private readonly object _eventLocker = new object();
/// <summary>
/// Called on a background thread via messaging
/// </summary>
public void QueueEvent(RealtimeProcessorMessage newRequest)
{
bool mergedRequest;
lock (_eventLocker)
{
if (_pendingRequest == null)
{
mergedRequest = false;
_pendingRequest = new Request(newRequest, _engine);
}
else
{
mergedRequest = true;
_pendingRequest.Merge(newRequest, _engine);
}
}
_eventAvailable.Set();
}
/// <summary>
/// This is running on its own thread
/// </summary>
private void EventLoop()
{
while (true)
{
// Block until something exists in _pendingRequest
_eventAvailable.WaitOne();
Request currentRequest;
lock (_eventLocker)
{
currentRequest = _pendingRequest;
_pendingRequest = null;
}
// CAN THIS EVER BE NULL?
if (currentRequest == null)
continue;
//do stuff with the currentRequest here
}
}
}
Yes, the if (currrentRequest == null) could evaluate to true. Consider two threads racing to call _eventAvailable.Set(). One completes the call and the other gets preempted. Meanwhile the EventLoop thread wakes up and completes an entire iteration of the loop. You now have a situation where _pendingRequest is null and the WaitHandle is still waiting to be signaled again.
I want to present an entirely different solution to the problem. It looks your code could be simplified by using the producer-consumer pattern. This pattern is most easily implemented using a blocking queue. The BlockingCollection class implements such a queue.
public sealed class RealtimeRunner : MarshalByRefObject
{
private BlockingCollection<Request> m_Queue = new BlockingCollection<Request>();
public void QueueEvent(RealtimeProcessorMessage newRequest)
{
m_Queue.Add(new Request(newRequest _engine));
}
private void EventLoop()
{
while (true)
{
// This blocks until an item appears in the queue.
Request request = m_Queue.Take();
// Process the request here.
}
}
}

WatiN unreliable for repeated downloads?

WatiN seems to not handle repeated download dialogs consistently:
foreach (string file in lstFiles)
{
// continue if no download link
if (!ie.Element([search criteria]).Exists) continue;
var btnDownload = ie.Element([search criteria]);
string fullFilename = workingDir + "\\" + file;
FileDownloadHandler download = new FileDownloadHandler(fullFilename);
using (new UseDialogOnce(ie.DialogWatcher, download))
{
btnDownload.ClickNoWait();
download.WaitUntilFileDownloadDialogIsHandled(30);
download.WaitUntilDownloadCompleted(150);
ie.RemoveDialogHandler(download);
}
}
Basically, I loop through a list of filenames that I expect to be available and click the download button. This usually works, but after so many downloads (it varies, sometimes everything that's available downloads, sometimes nothing) it will hang while waiting to handle the dialog. The button's identified correctly, the download dialog appears, it just isn't detected and handled. It isn't site-specific as similar methods on other sites are also met with variable success. Anyone encounter this before and know of a resolution?
edit: Repeated downloads do not work whatsoever in Server 2008. In Win7, this happens randomly after one or more successful repeated downloads.
The problem appears because IE File Download Dialog consist of 2 windows. WatiN DialogWatcher gets all the system windows and tries to handle them in foreach loop. After handling first correct dialog window DialogWatcher gets the next window wich has the same properties and is a valid Download Dialog. DialogWatcher starts waiting until this window is visible but it closes immediately after previos window is handled.
My solution is to return from foreach loop after any dialog is handled:
#region WatiN Copyright (C) 2006-2011 Jeroen van Menen
//Copyright 2006-2011 Jeroen van Menen
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#endregion Copyright
using System;
using System.Collections.Generic;
using System.Threading;
using WatiN.Core.Exceptions;
using WatiN.Core.Interfaces;
using WatiN.Core.Logging;
using WatiN.Core.Native.InternetExplorer;
using WatiN.Core.Native.Windows;
using WatiN.Core.UtilityClasses;
namespace WatiN.Core.DialogHandlers
{
/// <summary>
/// This class handles alert/popup dialogs. Every second it checks if a dialog
/// is shown. If so, it stores it's message in the alertQueue and closses the dialog
/// by clicking the close button in the title bar.
/// </summary>
public class DialogWatcher : IDisposable
{
private static IList<DialogWatcher> dialogWatchers = new List<DialogWatcher>();
private bool _keepRunning = true;
private readonly IList<IDialogHandler> _handlers;
private readonly Thread _watcherThread;
private bool _closeUnhandledDialogs = Settings.AutoCloseDialogs;
public Window MainWindow { get; private set; }
/// <summary>
/// Gets the dialog watcher for the specified (main) internet explorer window.
/// It creates new instance if no dialog watcher for the specified window exists.
/// </summary>
/// <param name="mainWindowHwnd">The (main) internet explorer window.</param>
/// <returns></returns>
public static DialogWatcher GetDialogWatcher(IntPtr mainWindowHwnd)
{
var window = new Window(mainWindowHwnd);
Logger.LogDebug("GetDialogWatcher mainhwnd: " + window.Hwnd + ", " + window.Title);
var toplevelWindow = window.ToplevelWindow;
Logger.LogDebug("GetDialogWatcher mainhwnd: " + toplevelWindow.Hwnd + ", " + toplevelWindow.Title);
CleanupDialogWatcherCache();
var dialogWatcher = GetDialogWatcherFromCache(toplevelWindow);
// If no dialogwatcher exists for the ieprocessid then
// create a new one, store it and return it.
if (dialogWatcher == null)
{
dialogWatcher = new DialogWatcher(toplevelWindow);
dialogWatchers.Add(dialogWatcher);
}
return dialogWatcher;
}
public static DialogWatcher GetDialogWatcherFromCache(Window mainWindow)
{
// Loop through already created dialogwatchers and
// return a dialogWatcher if one exists for the given processid
foreach (var dialogWatcher in dialogWatchers)
{
if (dialogWatcher.MainWindow.Equals(mainWindow))
{
return dialogWatcher;
}
}
return null;
}
public static void CleanupDialogWatcherCache()
{
var cleanedupDialogWatcherCache = new List<DialogWatcher>();
foreach (var dialogWatcher in dialogWatchers)
{
if (!dialogWatcher.IsRunning)
{
dialogWatcher.Dispose();
}
else
{
cleanedupDialogWatcherCache.Add(dialogWatcher);
}
}
dialogWatchers = cleanedupDialogWatcherCache;
}
/// <summary>
/// Initializes a new instance of the <see cref="DialogWatcher"/> class.
/// You are encouraged to use the Factory method <see cref="DialogWatcher.GetDialogWatcherFromCache"/>
/// instead.
/// </summary>
/// <param name="mainWindow">The main window handle of internet explorer.</param>
public DialogWatcher(Window mainWindow)
{
MainWindow = mainWindow;
_handlers = new List<IDialogHandler>();
// Create thread to watch windows
_watcherThread = new Thread(Start);
// Start the thread.
_watcherThread.Start();
}
/// <summary>
/// Increases the reference count of this DialogWatcher instance with 1.
/// </summary>
public void IncreaseReferenceCount()
{
ReferenceCount++;
}
/// <summary>
/// Decreases the reference count of this DialogWatcher instance with 1.
/// When reference count becomes zero, the Dispose method will be
/// automatically called. This method will throw an <see cref="ReferenceCountException"/>
/// if the reference count is zero.
/// </summary>
public void DecreaseReferenceCount()
{
if (ReferenceCount > 0)
{
ReferenceCount--;
}
else
{
throw new ReferenceCountException();
}
if (ReferenceCount == 0)
{
Dispose();
}
}
/// <summary>
/// Adds the specified handler.
/// </summary>
/// <param name="handler">The handler.</param>
public void Add(IDialogHandler handler)
{
lock (this)
{
_handlers.Add(handler);
}
}
/// <summary>
/// Removes the specified handler.
/// </summary>
/// <param name="handler">The handler.</param>
public void Remove(IDialogHandler handler)
{
lock (this)
{
_handlers.Remove(handler);
}
}
/// <summary>
/// Removes all instances that match <paramref name="handler"/>.
/// This method determines equality by calling Object.Equals.
/// </summary>
/// <param name="handler">The object implementing IDialogHandler.</param>
/// <example>
/// If you want to use RemoveAll with your custom dialog handler to
/// remove all instances of your dialog handler from a DialogWatcher instance,
/// you should override the Equals method in your custom dialog handler class
/// like this:
/// <code>
/// public override bool Equals(object obj)
/// {
/// if (obj == null) return false;
///
/// return (obj is YourDialogHandlerClassNameGoesHere);
/// }
/// </code>
/// You could also inherit from <see cref="BaseDialogHandler"/> instead of implementing
/// <see cref="IDialogHandler"/> in your custom dialog handler. <see cref="BaseDialogHandler"/> provides
/// overrides for Equals and GetHashCode that work with RemoveAll.
/// </example>
public void RemoveAll(IDialogHandler handler)
{
while (Contains(handler))
{
Remove(handler);
}
}
/// <summary>
/// Removes all registered dialog handlers.
/// </summary>
public void Clear()
{
lock (this)
{
_handlers.Clear();
}
}
/// <summary>
/// Determines whether this <see cref="DialogWatcher"/> contains the specified dialog handler.
/// </summary>
/// <param name="handler">The dialog handler.</param>
/// <returns>
/// <c>true</c> if [contains] [the specified handler]; otherwise, <c>false</c>.
/// </returns>
public bool Contains(IDialogHandler handler)
{
lock (this)
{
return _handlers.Contains(handler);
}
}
/// <summary>
/// Gets the count of registered dialog handlers.
/// </summary>
/// <value>The count.</value>
public int Count
{
get
{
lock (this)
{
return _handlers.Count;
}
}
}
/// <summary>
/// Gets or sets a value indicating whether unhandled dialogs should be closed automaticaly.
/// The initial value is set to the value of <cref name="Settings.AutoCloseDialogs" />.
/// </summary>
/// <value>
/// <c>true</c> if unhandled dialogs should be closed automaticaly; otherwise, <c>false</c>.
/// </value>
public bool CloseUnhandledDialogs
{
get
{
lock (this)
{
return _closeUnhandledDialogs;
}
}
set
{
lock (this)
{
_closeUnhandledDialogs = value;
}
}
}
/// <summary>
/// Gets the (main) internet explorer window handle this dialog watcher watches.
/// </summary>
/// <value>The process id.</value>
public IntPtr MainWindowHwnd
{
get { return MainWindow.Hwnd; }
}
/// <summary>
/// Called by the constructor to start watching popups
/// on a separate thread.
/// </summary>
private void Start()
{
while (_keepRunning)
{
if (MainWindow.Exists())
{
var winEnumerator = new WindowsEnumerator();
var windows = winEnumerator.GetWindows(win => true);
foreach (var window in windows)
{
if (!_keepRunning) return;
if(HandleWindow(window))
break;
}
// Keep DialogWatcher responsive during 1 second sleep period
var count = 0;
while (_keepRunning && count < 5)
{
Thread.Sleep(200);
count++;
}
}
else
{
_keepRunning = false;
}
}
}
public bool IsRunning
{
get { return _watcherThread.IsAlive; }
}
public int ReferenceCount { get; private set; }
/// <summary>
/// Get the last stored exception thrown by a dialog handler while
/// calling the <see cref="IDialogHandler.HandleDialog"/> method of the
/// dialog handler.
/// </summary>
/// <value>The last exception.</value>
public Exception LastException { get; private set; }
/// <summary>
/// If the window is a dialog and visible, it will be passed to
/// the registered dialog handlers. I none if these can handle
/// it, it will be closed if <see cref="CloseUnhandledDialogs"/>
/// is <c>true</c>.
/// </summary>
/// <param name="window">The window.</param>
/// <returns>
/// <c>true</c> if dialog is handled by one of handlers; otherwise, <c>false</c>.
/// </returns>
public bool HandleWindow(Window window)
{
if (!window.IsDialog()) return false;
if (!HasDialogSameProcessNameAsBrowserWindow(window)) return false;
// This is needed otherwise the window Style will return a "wrong" result.
WaitUntilVisibleOrTimeOut(window);
// Lock the thread and see if a handler will handle
// this dialog window
lock (this)
{
foreach (var dialogHandler in _handlers)
{
try
{
if (dialogHandler.CanHandleDialog(window, MainWindow.Hwnd))
{
if (dialogHandler.HandleDialog(window)) return true;
}
}
catch (Exception e)
{
LastException = e;
Logger.LogAction((LogFunction log) => { log("Exception was thrown while DialogWatcher called HandleDialog: {0}",e.ToString()); });
}
}
// If no handler handled the dialog, see if the dialog
// should be closed automatically.
if (!CloseUnhandledDialogs || !MainWindow.Equals(window.ToplevelWindow)) return false;
Logger.LogAction((LogFunction log) => { log("Auto closing dialog with title: '{0}', text: {1}, style: ", window.Title, window.Message, window.StyleInHex); });
window.ForceClose();
}
return false;
}
private bool HasDialogSameProcessNameAsBrowserWindow(Window window)
{
var comparer = new Comparers.StringComparer(window.ProcessName, true);
return comparer.Compare(MainWindow.ProcessName);
}
private static void WaitUntilVisibleOrTimeOut(Window window)
{
// Wait untill window is visible so all properties
// of the window class (like Style and StyleInHex)
// will return valid values.
var tryActionUntilTimeOut = new TryFuncUntilTimeOut(TimeSpan.FromSeconds(Settings.WaitForCompleteTimeOut));
var success = tryActionUntilTimeOut.Try(() => window.Visible);
if (!success)
{
Logger.LogAction((LogFunction log) => { log("Dialog with title '{0}' not visible after {1} seconds.", window.Title, Settings.WaitForCompleteTimeOut); });
}
}
#region IDisposable Members
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or
/// resetting unmanaged resources.
/// </summary>
public void Dispose()
{
lock (this)
{
_keepRunning = false;
}
if (IsRunning)
{
_watcherThread.Join();
}
Clear();
}
#endregion
}
}
My team ran into this as well while automating IE8 with WatiN. The problem seems to be with IE, possibly doing some time consuming house-cleaning. The work-around we ultimately used was to invoke a new instance of IE within the outer loop, disposing of it each iteration and then waiting for 5 seconds for whatever was going on in the background to resolve. It was a hack but got the job done.
foreach (var file in lstFiles)
{
string fullFilename = workingDir + "\\" + file;
using (var browser = new IE(fullFilename))
{
//page manipulations...
FileDownloadHandler download = new FileDownloadHandler(fullFilename);
using (new UseDialogOnce(browser.DialogWatcher, download))
{ //lnkFile.ClickNoWait();
download.WaitUntilFileDownloadDialogIsHandled(15);
download.WaitUntilDownloadCompleted(150);
}
}
Thread.Sleep(5000);
}

Is this BlockingQueue susceptible to deadlock?

I've been using this code as a queue that blocks on Dequeue() until an element is enqueued. I've used this code for a few years now in several projects, all with no issues... until now. I'm seeing a deadlock in some code I'm writing now, and in investigating the problem, my 'eye of suspicion' has settled on this BlockingQueue<T>. I can't prove it, so I figured I'd ask some people smarter than me to review it for potential issues. Can you guys see anything that might cause a deadlock in this code?
public class BlockingQueue<T>
{
private readonly Queue<T> _queue;
private readonly ManualResetEvent _event;
/// <summary>
/// Constructor
/// </summary>
public BlockingQueue()
{
_queue = new Queue<T>();
_event = new ManualResetEvent(false);
}
/// <summary>
/// Read-only property to get the size of the queue
/// </summary>
public int Size
{
get
{
int count;
lock (_queue)
{
count = _queue.Count;
}
return count;
}
}
/// <summary>
/// Enqueues element on the queue
/// </summary>
/// <param name="element">Element to enqueue</param>
public void Enqueue(T element)
{
lock (_queue)
{
_queue.Enqueue(element);
_event.Set();
}
}
/// <summary>
/// Dequeues an element from the queue
/// </summary>
/// <returns>Dequeued element</returns>
public T Dequeue()
{
T element;
while (true)
{
if (Size == 0)
{
_event.Reset();
_event.WaitOne();
}
lock (_queue)
{
if (_queue.Count == 0) continue;
element = _queue.Dequeue();
break;
}
}
return element;
}
/// <summary>
/// Clears the queue
/// </summary>
public void Clear()
{
lock (_queue)
{
_queue.Clear();
}
}
}
I think this could be your problem:
Thread 1 Thread 2
Dequeue
Enqueue
if (Size == 0) // Thread 1 gets the lock
lock (_queue) // Thread 2 has to wait
return _queue.Count // Thread 1 sees: Size == 0
_queue.Enqueue // Thread 2 gets the lock
_event.Set
_event.Reset // uh oh
_event.WaitOne // now Dequeue's going to block
// until Enqueue gets called again
// (even though queue isn't empty)
This code is broken in several ways. Here's one scenario. There's a race-condition between if (Size == 0) and _event.Reset(). An Enqueue might fire between the two, and its signal will be lost.
An unounded-length BlockingQueue is much more easily implemented with a semaphore.
I don't know about your requirements or what else your class does, but if you can use .NET 4, you might want to consider using ConcurrentQueue<T> and BlockingCollection<T> which, used together, should give you a blocking queue.

Categories