How can I do a Monitor.Wait with processing message queue? - c#

I'm using .NET 4.0 (no async).
I'm looking for a combination of Monitor.Wait and Application.Run. I've browse object explorer but I can't find one.
Does it exists ? If not, what is the best way to implement it ?
I've still tried nothing because what I have in mind is very dirty. Something like this :
while (!(timeOutHasBeenReached || aLockHasBeenAcquired))
{
Application.DoEvents() ;
}
To avoid XY problem, let me introduce the final goal (relates to unit testing) :
using (ApplicationContext applicationContext = new ApplicationContext())
{
using (Control control = new Control() { Visible = true } )
{
// control will do something across the web
// When the control has done it, it will raise an event invoking applicationContext.Exit()
// As a web connection is not always timing trustfull I'd like
// to specify a timeout (or eventually abort it with a Monitor.Pulse)
Application.Run(applicationContext);
}
}
Control is a Winform component which I can't modify and I don't want to do Thread.Abort .

Can't you abort by doing control.Invoke(() => Application.Exit());? Or just control.Close(); or Dispose.

Related

Begin Invoke is not running

Im using System.Windows.Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() => ... for a wpf graphic refresh.
It works in my other function greatfully, but in my SQL delete function it wount be triggered/executed.
I tried it with System.Windows.Forms.Application.DoEvents(); but it wount do anything.
Set_Loading_Changed()
{
System.Windows.Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Input,
new Action(() =>
{
if (BLoading)
{
DataGrid_Anzeige.IsEnabled = false;
Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;
}
else
{
DataGrid_Anzeige.IsEnabled = true;
Mouse.OverrideCursor = null;
}
}));
}
Btn_Remove()
{
...
Set_Loading_Changed();
using (OleDbConnection ODC = new OleDbConnection("..."))
{
foreach (var selectedRow in DataGrid_Anzeige.SelectedItems.OfType<DataRowView>())
{
sSQL_Statement = "...";
ODC.Open();
OleDbCommand ODCmd = new OleDbCommand(sSQL_Statement, ODC);
ODCmd.ExecuteNonQuery();
ODC.Close();
EDIT:
I insert the complete part of my Set_Load_Changed() function, hope you can get a clue with this informations.
Im using it primarly in my search Thread (Task.Factory.StartNew(() => { ... }));) so it must be the DispatcherPriority.Input.
You're running into a common issue with misunderstanding the WPF threading system. The way WPF is structured is with one thread for the program to run and modify the UI in, usually called the UI thread, and a second thread which you have no normal way of using, which automatically renders the UI, commonly called the rendering or compositing thread.
The key point you need to know here is that if you stall the UI thread with a large operation (like a database read or a large calculation) immediately after BeginInvoke(), then you're preventing the UI thread from running those commands until you allow it to invoke the next action. BeginInvoke() simply queues the action to be performed the next time the dispatcher is allowed - the dispatcher will not interrupt what is currently being done. Setting the priority to Input ensures that it will be handled ahead of other lower priority work, but still will not cause it to interrupt your current method.
If you instead call Invoke(), you are interrupting your work to ask the dispatcher to perform the action and then return to what you're doing when it's finished.
While this is preferable to the behavior you're currently getting, this isn't how you're intended to use the dispatcher, and will still cause your app to appear 'frozen' while it completes the long operation. To avoid this, the easiest thing to do is run the long operation in a Task, using the async/await keywords and the Task Parallel Library.
Stephen Cleary has an excellent blog where he covers a lot of topics related to this. His introductory post (dating back to the keywords' introduction) is here.
I would encourage poking around his blog if you have more issues in this area - he's one of the leading experts in explaining this area, and has covered most of the problems you run into.
Further reading:
What's the difference between Invoke() and BeginInvoke()?
WPF Threading Model
To change the cursor in WPF is unfortunately not as straightforward as in WinForms. I remember struggling with it myself until I stumbled upon the following solution. I didn't come up with this myself, I'll try and find the source to give credit where it is due.
using System;
using System.Collections.Generic;
using System.Windows.Input;
namespace MyNamespace
{
public class OverrideCursor : IDisposable
{
static Stack<Cursor> s_Stack = new Stack<Cursor>();
public OverrideCursor(Cursor changeToCursor = null)
{
if (changeToCursor == null)
changeToCursor = Cursors.Wait;
s_Stack.Push(changeToCursor);
if (Mouse.OverrideCursor != changeToCursor)
Mouse.OverrideCursor = changeToCursor;
}
public void Dispose()
{
s_Stack.Pop();
var cursor = _stack.Count > 0 ? _stack.Peek() : null;
if (Mouse.OverrideCursor != cursor)
Mouse.OverrideCursor = cursor;
}
}
}
Now this disposable class can be used anywhere in your project to change the cursor temporarily.
using (new OverrideCursor())
{
//your code
}
This will change the cursor to anything you want by passing the cursor as parameter of the constructor, or nothing to use Cursors.Wait by default.
For the time needed to execute any code placed inside the using-block the cursor will be changed turning back to normal afterwards.
You can also initiate an object of the class without the using-block to set it indefinitely but you shouldn't forget to call Dispose() when done.
Edit: source: https://stackoverflow.com/a/675686/4579864
If want to do whatever you are doing in Set_Loading_Changed() before you connect to the database, you should call Invoke instead of BeginInvoke:
Set_Loading_Changed()
{
System.Windows.Application.Current.Dispatcher.Invoke(...);
}
What's the difference between Invoke() and BeginInvoke()

Make my COM assembly call asynchronous

I've just "earned" the privilege to maintain a legacy library coded in C# at my current work.
This dll:
Exposes methods for a big legacy system made with Uniface, that has no choice but calling COM objects.
Serves as a link between this legacy system, and another system's API.
Uses WinForm for its UI in some cases.
More visually, as I understand the components :
*[Big legacy system in Uniface]* ==[COM]==> [C# Library] ==[Managed API]==> *[Big EDM Management System]*
The question is: One of the methods in this C# Library takes too long to run and I "should" make it asynchronous!
I'm used to C#, but not to COM at all. I've already done concurrent programming, but COM seems to add a lot of complexity to it and all my trials so far end in either:
A crash with no error message at all
My Dll only partially working (displaying only part of its UI, and then closing), and still not giving me any error at all
I'm out of ideas and resources about how to handle threads within a COM dll, and I would appreciate any hint or help.
So far, the biggest part of the code I've changed to make my method asynchronous :
// my public method called by the external system
public int ComparedSearch(string application, out string errMsg) {
errMsg = "";
try {
Action<string> asyncOp = AsyncComparedSearch;
asyncOp.BeginInvoke(application, null, null);
} catch (ex) {
// ...
}
return 0;
}
private int AsyncComparedSearch(string application) {
// my actual method doing the work, that was the called method before
}
Any hint or useful resource would be appreciated.
Thank you.
UPDATE 1:
Following answers and clues below (especially about the SynchronizationContext, and with the help of this example) I was able to refactor my code and making it to work, but only when called from another Window application in C#, and not through COM.
The legacy system encounters a quite obscure error when I call the function and doesn't give any details about the crash.
UPDATE 2:
Latest updates in my trials: I managed to make the multithreading work when the calls are made from a test project, and not from the Uniface system.
After multiple trials, we tend to think that our legacy system doesn't support well multithreading in its current config. But that's not the point of the question any more :)
Here is a exerpt of the code that seems to work:
string application;
SynchronizationContext context;
// my public method called by the external system
public int ComparedSearch(string application, out string errMsg) {
this.application = application;
context = WindowsFormsSynchronizationContext.Current;
Thread t = new Thread(new ThreadStart(AsyncComparedSearchAndShowDocs));
t.Start();
errMsg = "";
return 0;
}
private void AsyncComparedSearch() {
// ANY WORK THAT AS NOTHING TO DO WITH UI
context.Send(new SendOrPostCallback(
delegate(object state)
{
// METHODS THAT MANAGE UI SOMEHOW
}
), null);
}
We are now considering other solutions than modifying this COM assembly, like encapsulating this library in a Windows Service and creating an interface between the system and the service. It should be more sustainable..
It is hard to tell without knowing more details, but there are few issues here.
You execute the delegate on another thread via BeginInvoke but you don't wait for it. Your try\catch block won't catch anything as it has already passed while the remote call is still being executed. Instead, you should put try\catch block inside AsyncComparedSearch.
As you don't wait for the end of the execution of remote method (EndInvoke or via callback) I am not sure how do you handle the results of the COM call. I guess then that you update the GUI from within AsyncComparedSearch. If so, it is wrong, as it is running on another thread and you should never update GUI from anywhere but the GUI thread - it will most likely result with a crash or other unexpected behavior. Therefore, you need to sync the GUI update work to GUI thread. In WinForms you need to use Control.BeginInvoke (don't confuse it with Delegate.BeginInvoke) or some other way (e.g. SynchronizationContext) to sync the code to GUI thread. I use something similar to this:
private delegate void ExecuteActionHandler(Action action);
public static void ExecuteOnUiThread(this Form form, Action action)
{
if (form.InvokeRequired) { // we are not on UI thread
// Invoke or BeginInvoke, depending on what you need
form.Invoke(new ExecuteActionHandler(ExecuteOnUiThread), action);
}
else { // we are on UI thread so just execute the action
action();
}
}
then I call it like this from any thread:
theForm.ExecuteOnUiThread( () => theForm.SomeMethodWhichUpdatesControls() );
Besides, read this answer for some caveats.

Using LocalMessageSender synchronously

We have an application that has a primary window, it can launch multiple other windows, in new browsers. We are using a silverlight application as a coordinating server in the primary window to close all windows that are part of the app, regardless of the way they are opened (we can't guarantee it was via window.open so don't always have a handle to the window in javascript).
On log out, we want to signal all the other windows to perform an auto-save, if necessary, then close down.
So all windows have a silverlight app, they coordinate using localmessagesenders. However, these are asynchronous:
private void ProcessAutosave()
{
foreach (string s in _windows)
{
SendMessage(s, "notify-logout");
}
// code here quoted later...
}
// sendasynch doesn't send until the method terminates, so have to do it in it's own function.
private void SendMessage(string to, string message)
{
var lms = new LocalMessageSender(to);
lms.SendCompleted += new EventHandler<SendCompletedEventArgs>(SenderSendCompleted);
lms.SendAsync(message);
}
Since the ProcessAutosave is called from a javascript onunload event which can't be cancelled, we need this to be synchronous and not complete before we have a response processed from each sub-window so the session state will still be valid etc.
In the SenderSendCompleted we remove items from _windows when they have said they're done.
So I added a loop on the end:
while(_windows.Count > 0) {
Thread.Sleep(1)
}
However, that never terminates, unless I put an iteration counter on it.
Am I the victim of a compiler optimisation meaning the changes in SenderSendCompleted do not affect that while loop, or, have I fundamentally misunderstood something? Or missed something obvious that's staring me in the face?
It sounds like a subtle verson of a race situation due to going sync/async. Couldn't the process in queston also receive notifications from the windows that they have received the message and are shutting down? Once all of the counter messages have been received, then the main app could shut down without the busy wait at the end(?).
I have found a way to work round. However, this does not really "solve" the problem generally, just in my case, which is also only supporting internet explorer.
function WindowCloseEventHandler()
{
var app = // get silverlight app handle...
app.doAutoSave();
var params = 'whatever you need';
var args = new Object();
args.hwnd = window;
window.showModalDialog('blocker.aspx',args,params);
}
function checkAutoSave()
{
var app = // get silverlight app handle...
return app.autosavecomplete();
}
Then in blocker.aspx we display a static "performing logout handlers" type message and do:
function timerTick()
{
if(window.dialogArguments.hwnd.checkAutoSave()) {
window.close();
} else {
setTimeout(timerTick, 500);
}
}
And start the timer on window load.
The child window's silverlight apps are notified to start an autosave, then they notify the parent when they are done. We then poll the parent's status from a modal dialog, which blocks the termination of the WindowCloseEventHandler() which we have wired up to the onclose event of the body.
It's hacky and horrible, but it means silverlight stays asynchronous and we're using a javascript timer so the javascript isn't loading the system.
Of course if the user closes the modal dialogue, there is a potential for issue.

Directshow in c# compact framework: trigger handling problems for a Filtergraph's IMediaEvent

I'm working on implementing directshow capability in a C# dll. I'm basing my work off of the C++ based "CameraCapture" example Microsoft provides with the Windows Mobile 6 sdk.
Things were going well (thanks to earlier help on this site), but I've run into a bit of a snag while trying to listen for directshow events in C# land:
I have a thread that loops to listen for dshow events. It waits based on a manual reset event that gets defined here (this is defined at the end of graph initialization: the graph is built, renderstream is called, and controlstream is already blocking dataflow):
DshowRequestMan = new ManualResetEvent(false);
MediaEvent = (IMediaEvent)FilterGraph;
chk(MediaEvent.GetEventHandle(out DshowEventHandle));
DshowRequestMan.Handle = DshowEventHandle; //note: no "SafeHandle" in cf
There are 2 related problems I'm experiencing with this:
When my dshow event handler loop pulls the event via IMediaEvent.GetEvent() using a timeout of 0, I get a "timeout exceeded" hresult (-2147467260) on the third iteration. That third event trigger (and subsequent error) don't occur in the C++ example.
If I ignore the timeout case mentioned above, it will constantly trigger with a 73 event. This kills the processor since the loop basically never pauses.
When the C++ example runs its graph in preview mode, it gets two IMediaEvents: first 13, then 73. After that, it stops triggering until actual capturing is started. My C# version pulls 13, then 73, then 73 again, but with the timeout error.
In short, it seems like that third triggering of the DshowRequestMan shouldn't be happening because there is no dshowevent to actually "get", hence, the timeout.
Not sure what I'm doing wrong- I'm calling "FreeEventParams()" with each iteration... I'm suspecting the ManualResetEvent object is being used incorrectly since I'm just assigning something to its handle property, but the same thing happens when I use a Pinvoked "WaitForSingleObject" to listen to the DshowEventHandle... I'm confused at this point.
Any ideas would be greatly appreciated. Thanks in advance!
Here is my code for filter graph event handling:
while (!_stopReceivingEvents) {
IntPtr eventHandle;
var hr = _mediaEvent.GetEventHandle(out eventHandle);
DsError.ThrowExceptionForHR(hr);
//NOTE: Do not close the event handle, because it is used internally by the filter graph
using (var safeWaitHandle = new SafeWaitHandle(eventHandle, false)) {
using (var waitHandle = new AutoResetEvent(false) {SafeWaitHandle = safeWaitHandle}) {
if (WaitHandle.WaitAll(new[] {waitHandle}, 500)) {
//receive all available events
do {
EventCode eventCode;
IntPtr param1;
IntPtr param2;
hr = _mediaEvent.GetEvent(out eventCode, out param1, out param2, 500);
_mediaEvent.FreeEventParams(eventCode, param1, param2);
if (hr == 0) {
switch (eventCode) {
//add handling code here
}
}
} while (hr == 0);
}
}
}
}
Are you making sure to Reset you event after you get and handle it?
Whatr does your actual wait code look like? The problem is likely that you're waiting for 0ms, which basically means "check the event and return immediately." If you want it to block on the wait (like a native call with WAIT_INFINITE) you need to pass in System.Threading.Timeout.Infinite (which is actually -1).
If you want the checking thread to periodically yield (which is way safer than an infinite wait and will actually allow your app to shut down), then you need to check the return from the wait, and if it's a timeout (0x80004004) then just go back and wait again:
while(!shutdown)
{
if(DshowRequestMan.WaitOne(1000))
{
// handle the event
}
}

FileSystemWatcher Dispose call hangs

We just started running in to an odd problem with a FileSystemWatcher where the call to Dispose() appears to be hanging. This is code that has been working without any problems for a while but we just upgraded to .NET3.5 SP1 so I'm trying to find out if anyone else has seen this behavior. Here is the code that creates the FileSystemWatcher:
if (this.fileWatcher == null)
{
this.fileWatcher = new FileSystemWatcher();
}
this.fileWatcher.BeginInit();
this.fileWatcher.IncludeSubdirectories = true;
this.fileWatcher.Path = project.Directory;
this.fileWatcher.EnableRaisingEvents = true;
this.fileWatcher.NotifyFilter = NotifyFilters.Attributes;
this.fileWatcher.Changed += delegate(object s, FileSystemEventArgs args)
{
FileWatcherFileChanged(args);
};
this.fileWatcher.EndInit();
The way this is being used is to update the state image of a TreeNode object (adjusted slightly to remove business specific information):
private void FileWatcherFileChanged(FileSystemEventArgs args)
{
if (this.TreeView != null)
{
if (this.TreeView.InvokeRequired)
{
FileWatcherFileChangedCallback d = new FileWatcherFileChangedCallback(FileWatcherFileChanged);
this.TreeView.Invoke(d, new object[]
{
args
});
}
else
{
switch (args.ChangeType)
{
case WatcherChangeTypes.Changed:
if (String.CompareOrdinal(this.project.FullName, args.FullPath) == 0)
{
this.StateImageKey = GetStateImageKey();
}
else
{
projectItemTreeNode.StateImageKey = GetStateImageKey();
}
break;
}
}
}
}
Is there something we're missing or is this an anomoly from .NET3.5 SP1?
Just a thought... Any chance there's a deadlock issue here?
You're calling TreeView.Invoke, which is a blocking call. If a filesystem change happens just as you're clicking whatever button causes the FileSystemWatcher.Dispose() call, your FileWatcherFileChanged method will get called on a background thread and call TreeView.Invoke, which will block until your form thread can process the Invoke request. However, your form thread would be calling FileSystemWatcher.Dispose(), which probably doesn't return until all pending change requests are processed.
Try changing the .Invoke to .BeginInvoke and see if that helps. That may help point you in the right direction.
Of course, it could also be a .NET 3.5SP1 issue. I'm just speculating here based on the code you provided.
Scott, we've occasionally seen issues with control.Invoke in .NET 2. Try switching to control.BeginInvoke and see if that helps.
Doing that will allow the FileSystemWatcher thread to return immediately. I suspect your issue is somehow that the control.Invoke is blocking, thus causing the FileSystemWatcher to freeze upon dispose.
We are also having this issue. Our application runs on .Net 2.0 but is compiled by VS 2008 SP1. I have .NET 3.5 SP1 installed as well. I've got no idea why this happens either, it doesn't look like a deadlock issue on our end as no other threads are running at this point (it is during application shutdown).

Categories