In my winforms client application, I have generated asynchronous methods for my WCF service (Begin... and End...).
When the application starts, it makes async calls to the server to get and cache data that will be later used in the application (e.g. list of countries).
If the application's main thread requires this data (e.g. to fill a combobox) before the async call had a chance to complete, I would like to block the main thread until the async call had Ended. I want to avoid making redundant calls to the WCF server.
I have tried to use a Monitor/Mutex and called Monitor.Enter(countryLock) then BeginGetCountries in the main thread and Monitor.Exit(countryLock) when the EndGetCountries method is called. However, I am facing the following exception:
Object synchronization method was called from an unsynchronized block of code.
Am I supposed to call Monitor.Exit(...) on the same thread that called Monitor.Enter(...)? If yes, how can I know the owner of the Monitor object and make a call in its context?
No, you don't want really to block the main thread. What you want to do is set a flag that the operation is pending and disable parts of your UI that depend on the result. When the result is returned from the asynchronous WCF operation, you can enable those parts of the UI and populate the data.
if you block the main thread it will give the appearance that the application has halted and that will be a poor experience for your users.
Like Peter Richie said, you don't want to lock in your UI thread. A "busy" flag is all you need, really.
Secondly, trying to do this with Monitor.Enter like you describe would not work, as the same thread is allowed to enter the same monitor twice without blocking.
And if you do lock, then yes, you are supposed to call Monitor.Exit(...) on the same thread that called Monitor.Enter(...). If that was the only only problem, you could marshal this back to the UI thread with this.BeginInvoke(). But like I said, locking with Monitor in a single threaded scenario makes no sense.
Related
I am writing a library, and would like to be able to fire a callback on a specified thread, so the end-user does not have to worry about thread-safety.
I tried using ExecutionContext, but that didn't work out too well, it would fire in the specified context (a new thread), but not on the thread that originally called the function.
The code should work like this:
void Connect() {
// This should be in the same thread ..
SocketAsyncEventArgs.Completed += eventHandler;
Socket.ConnectAsync(SocketAsyncEventArgs)
}
void eventHandler() {
// .. as this
}
You can't just run your code on some existing thread. That thread is already executing other code. But, it can provide you some way to run your code on it. The main thread in a WPF application does this using Dispatcher.Invoke(). The main thread of a WinForms application uses Control.Invoke().
There is a more general way to do this: use Synchronization.Context.Current. This would work for the main thread of WPF or WinForms application, but would execute the callback on a thread pool thread otherwise. (Unless there is some sort of custom synchronization context, which I think is very rare.)
But this is the best you can do. Like I said, you can't run your code on some other thread when you want. The code in that other thread has to allow you to do that.
That's the thing about asynchronous functions -- you can't guarantee when you'll get called back, or what thread will be running your callback function. Consider that the cost of being able to "set it and forget it".
There's usually no need for that much control anyway. If you "need" to have a specific thread run your callback, what you really need is to review why that's necessary. If it's something that needs to run on the UI thread, there's Control.Invoke. (The UI thread anticipates needing to be handed stuff to do, because of how the architecture works, so controls have a way to pass callbacks to run on that thread. You can't just up and do that with arbitrary threads -- they have to be expecting to be passed a callback like that.) Otherwise, if you have an issue with locks or something, chances are you're trying to use asynchronous functionality to do stuff that should really be done synchronously in a separate thread.
I've created a Windows service based on the ServiceBase class. In this service I created an instance of the NamedPipeClientStream (m_Stream). After connecting this stream I start an asynchronous read using the BeginRead() method:
m_Stream.BeginRead( m_ReadBuffer, 0, 2, ReadAsyncCallback, m_ReadInfo );
In the callback routine ReadAsyncCallback, which indeed gets called, I call EndRead() for the stream (which gives me the number of bytes read, in this case 2). Next, I want to signal the original thread that the read has been completed. For this I use the Dispatcher.Invoke method:
m_Dispatcher.Invoke( new ReadDelegate( this.OnRead ), bytesRead);
(m_Dispatcher was created in the original thread using System.Windows.Threading.Dispatcher.CurrentDispatcher.)
At this point I expected the OnRead method to get called in the original thread, but it doesn't. The Invoke() method doesn't return, it seems to 'hang'.
I hope someone can help me with this. Please let me know if you need more info, I will try to give it to you asap.
Greetings,
Richard
The System.Windows.Threading.Dispatcher requires a correctly configured SynchronizationContext in order for it to work as you normally expect. When in the context of a WPF application the synchronization context is automatically created for you, however in your Windows Service that does not happen and that's why you see the hang.
Also, aside the synchronization context, since I believe the Dispatcher works in a similar way to the Control.Invoke or BackgroundWorker in Windows Forms, your Windows Service main thread must be pumping a message loop in order for you to be able to inject your call into it.
I have written a blog about how the BackgroundWorker class reacts differently according to the context in which its run (Windows Forms, Console or Windows Service), which you may find to be an interesting read since the mechanism used by that class is similar to the WPF Dispatcher.
Inside BackgroundWorker
Finally, for a more in depth dive into how the synchronization contexts work you should read:
It's All About the SynchronizationContext
The thread that called CurrentDispatcher is probably not pumping messages for some reason. The most likely reason is because it does not have any message pumping mechanism. For Invoke to work correctly the target thread must be specially designed to accept delegate injections. This is usually accomplished by having the target thread spin in an infinite loop waiting for messages to appear in a queue. Another thread would then submit a special message requesting the execution of a delegate. This is all setup automatically on the UI thread of Windows Forms or WPF applications. It will not exist in Windows Service application unless you get it going manually.
I would not attempt to use this delegate marshaling technique (or any technique that synchronously injects a delegate into another thread) anyway. The reason is because it will cause that asynchronous IO callback, which is executing on a ThreadPool thread or IO completion port thread, to block until that marshaled delegate completes. You do not want to tie up the IO in this manner.
Instead you should publish the data that is read from the stream into a shared data structure, like a queue or list, and then have your original thread pick it up on a specific interval. If the original thread is expected to wait for data to be read from the stream then you could setup the producer-consumer pattern. This is pretty easy with the BlockingCollection. The original thread will call Take which will block until an item arrives and the IO callback will publish the data by calling Add.
There are other acceptable ways this could be handled, but calling Invoke is probably not one of them.
Assume that I have Silverlight app doing a call to a WCF service:
void DoStuff()
{
MyProxy proxy = new MyProxy();
proxy.DoStuffCompleted += DoStuffCompleted;
proxy.DoStuffAsync();
}
void DoStuffCompleted(object sender, DoStuffCompletedEventArgs e)
{
// Handle the result.
}
DoStuff is called by the UI thread. What thread will eventually call the DoStuffCompleted method? If I invoke two async calls at the same time, is there a possibility that both the completed events are fired simultaneously, on different threads?
The callback will be invoked on the main thread. Multiple responses will not occur simultaneously. The order of the response events could be unexpected. You may want to use the overload of proxy.DoStuffAsync that accepts "user state" object:
proxy.DoStuffAsync(object userState)
This will allow you to send something unique for each call so you can differentiate which response you're dealing with. Remember that if the WCF call returns an error you have no return value - so userState may be the only way to know which call failed (if it matters).
Update:
Found some more info (on SO) on how to make it use another thread:
Silverlight web service callback performance Follow the link there to Tomek's blog for lots more info.
The Completed event will occur on a different thread than the UI Thread. Multiple Completed events may be executed simultaneously on different threads because a thread pool is used to handle results.
Asynch calls are executed in the background thread pool. For each asynch call you shall have a separate thread from the pool.
DoStuffCompleted will be executed in the background pool thread.
Now, it is important to note that this
method is called on the background
worker thread. If we want to update
the UI with the newly obtained data
(say we want to update a data grid
control to display the customer data),
we have to be careful to do this on
the UI thread. If we don't, then all
manner of strange things may happen
and we will have a difficult time
diagnosing which bug to fix (from here)
I haven't been able to find an example like this, though I'm sure there must be a few out there.
When the user clicks a button to log in, an event handler on the button click calls a function that logs the user in. Based on the user, they can be taken to one of many start screens. The information for which screen is returned from a service call. From what I can tell, Dispatcher.BeginInvoke is only used to update the UI thread, so the logic that determines which page to navigate to should be in the method passed to Dispatcher.BeginInvoke, right?
I need to make a service call and take action based on the result. Do I have to make the async service call first and call Dispatcher from the callback? Do I put the function that does the validation, calls the service, and handles the callback as the delegate that is passed to the Dispatcher?
Sorry if this is a basic question. The examples I've found only use the Dispatcher to update a textbox or some other trivial item. I haven't found anything where the UI thread needs to take action based on the result of an async call.
It's not clear what validation you're talking about but:
Call the service asynchronously, with a callback to execute when the service call finishes
In the callback, do whatever non-UI related work is involved, and then call Dispatcher.BeginInvoke to perform any UI-related operations.
If you need to do validation before the service call, that could be part of your button's event handler... at least as long as it isn't a long-running piece of validation.
If you could give more details about what steps are logically involved in your process, that would help.
See, Dispatcher actually holds the UI thread. As every control has strong thread affinity, you need to update this using Dispatcher.
From any thread you can access Dispatcher using DispatcherObject.Dispatcher.
this.Dispatcher.Invoke((Action)(()=>{
.//// your action
});
Now whenever you need to update the elements in the thread, you can wrap around the context to call service anytime. You can use the Background thread or you can call from inside of Dispatcher thread to invoke the Service call.
Calling From dispatcher will hold the UI if the call is synchronous. So I recommend you to do the call from the Background thread just below updating the Invoker.
All service call are asynchronous in silverlight (and hence windows phone 7) so yes, what you describe is way you do it.
Different service libraries provide different ways to call their methods - some offer a 'call complete' method, others take a event hander passed in, but either way if you want to update the UI (and I assume this includes moving page) you will need to do this on the UI thread, which is what the dispatcher is for.
Dispatcher.BeginInvoke( () => {
// This code is on the UI thread.
});
I currently have a thread that listens for data from the network and then runs rules on it. I then want to pass the data to the GUI. I am worried about having a deadlock in the GUI. I cant figure out were to put the mutexes on the GUI side. I am also using c# and dotnet 3.5.
What I have come up with is
1) Using a timer to create an event and dump the thread. Worried about performance.
2) Use an intermediary event to copy the data to GUI.
3) Dig in and figure out thread safe way of using GUI.
What do you think is best way to proceed?
Edit: Here is the solution I am using. I pass in the changed element and then protect the big object with a mutex. I use helper function to switch threads using InvokeRequired then BeginInvoke with a delegate. Pulled from reading the answers and then following links until reaching Threading in Windows Forms by Jon Skeet.
delegate void UInt32ParameterDelegate(UInt32 n);
public void UpdateLocation(UInt32 n)
{
if (InvokeRequired)
{
// We're not in the UI thread, so we need to call BeginInvoke
BeginInvoke(new UInt32ParameterDelegate(UpdateLocation), new object[] { n });
return;
}
// Must be on the UI thread if we've got this far
this.engine.location.UpdateBusy.WaitOne();
// do the work in here
this.engine.location.UpdateBusy.ReleaseMutex();
}
Synchronization is very easy in Windows Forms. You can call Control.Invoke() in the background thread. The thread will stall until the delegate has finished running on the UI thread. No sync required at all.
If stalling the thread is a problem, use Control.BeginInvoke(). You'll have to protect the object(s) you pass to the delegate with a lock if the thread might alter them while it continues running. That's rarely the case in a producer-consumer scenario, the thread can simply create new objects.
Do make sure that you don't Invoke() too often. Do it more frequently than about 1000 times per second and the UI thread will stop pumping Windows messages, being bogged down by handling the invoke requests. Since it is human eyes you're trying to please, invoking more than about 25 times per second is just wasted effort. Pool intermediate results in a collection object.
I hope I understand your problem correctly.
After the background thread reads the data and does whatever it wants, it should use Invoke to call a method on the GUI thread. That method would update anything that should be updated in the GUI.
Never read from the network on the GUI thread. It's only a matter of time before your application runs during a network outage and your GUI hangs as a result. This will really frustrate your users.
In your situation I think the best approach is to have a background thread complete the read operation. Then take the resulting data and move it back to the GUI thread via a SynchronizationContext Post or Send method.
you should just pass an event from your network thread to your UI thread.
then cross threads using begininvoke so you don't get a cross thread exception.
Need help getting info across a UI thread and another thread in C#
You could use a backgroundworker that will process the datareading in a background thread and when it's done you can end the backgroundworker triggering it's RunWorkerCompletedEventHandler. In the RunWorkerCompletedEventHandler you can update your GUI thread with the result.
Isn't easier to just throw a delegate who raise an event that inform the form to refresh itself?