I'm trying to maintain some horrible VB to get concurrency.
I want to delegate some Maths code to a thread and have it raise an event with EventArgs which contains a structure with the information with which to update a form. In the UI event handler, I'm using BeginInvoke so as not to block the thread because the UI update takes quite a bit of time, but the thread needs to carry on with the next set of Maths.
The previous programmer implemented a timer to call the Maths code and there are a gnats swarm of global variables which represent the results; no way can I implement data locking, it's too big change. The problem with the timer solution is that the Maths code can't run while the UI is being updated (at a slower rate). I've also considered splitting up the UI code across many timer events but this is also quite irksome to achieve to get a balance across the cycles.
Are the EventArgs thread safe i.e. if the UI starts to use the passed EventArgs and the thread generates another event, OR should the UI clone a copy before control is transferred to the UI thread ?
I've written some test code which looks like this.
Private Observed As UIDelegatePattern.Observed
Private Delegate Sub ProcessDelegate(ByVal sender As Object, ByVal e As UIDelegatePattern.Observed.ProcessEventArgs)
Private Sub Render(ByVal sender As Object, ByVal e As UIDelegatePattern.Observed.ProcessEventArgs)
If Me.InvokeRequired Then
Dim d As ProcessDelegate = New ProcessDelegate(AddressOf Render)
' invoke on the UI thread asynchronously
Me.BeginInvoke(d, New Object() {sender, e})
Else
' prevent event overflow by removing the handler before the long rendering activity
RemoveHandler Observed.EventHandler, AddressOf Render
' simulate many controls updates
For i As Integer = 0 To 1000
Me.Label1.Text = e.Message
Next
Me.Update()
Me.Refresh()
Application.DoEvents()
' add the handler back in for next time
AddHandler Observed.EventHandler, AddressOf Render
End If
End Sub
You've got a lot of information, and possible some other questions implied, in that post. But to be specific, as long as the class that is raising the event creates a new EventArgs on each notification then you are fine and do not need to copy the EventArgs in the event listener.
Related
I'm using ExcelDNA to develop an XLL.
In it, I have a form living in a DLL to which I pass "ExcelDnaUtil.Application" as a member to facilitate interactions between the form and the instance of Excel running the XLL.
If I launch the form in the main thread using:
form1.show()
when I close the form then close Excel, Process Explorer shows that the Excel process is properly disposed of.
If I launch the form using a new thread:
Dim workerThread As Thread
workerThread = New Thread(Sub() form1.showdialog())
workerThread.Start()
when I close the form and then close Excel, the process remains in Process Explorer. I have been careful not to use two decimal points in any line of code and set the interface member to "nothing" when closing the form. I am not using "ReleaseCOMObject" as other articles have indicated that it is bad-practice.
Question: How do I dispose of the Excel process properly from a separate thread?
It's impossible to get the COM stuff right cross-thread.
You should never talk to the Excel COM object model from another thread. If you follow this one simple rule, you never have to worry about two dots, never have to set anything to Nothing and never have to call any of the ReleaseComObject hacks. And Excel will close nicely.
Since Excel is single-threaded (actually because the Excel COM object model lives in a Single-Threaded Apartment), there is no performance benefit from talking to Excel with another thread - internally it all gets marshalled to the main thread anyway.
If you dare to talk to Excel from another thread, then any COM call could fail, at any time. This is because Excel is still 'alive' and can go into a state where the 'object model is suspended', causing all COM calls to fail (with errors that even a COM message filter can't catch). When would Excel go into such a stubborn mode? When the user does something crazy like click their mouse button, for example.
How then to call back to Excel after you've done some work on another thread? Excel-DNA has a helper that will schedule work to be done back on the main thread, when Excel is in a mode where COM calls are safe. You just call ExcelAsyncUtil.QueueAsMacro(...) with a delegate containing the work to be done. This call can be made at any time from any thread, but the code will only run when ready.
A somewhat clumsy example is this:
Public Module MyFunctions
Dim workerThread As Thread
Public Function OverwriteMe() As Object
Dim caller = ExcelDnaUtil.Application.Caller
workerThread = New Thread( _
Sub()
Thread.Sleep(5000)
ExcelAsyncUtil.QueueAsMacro( _
Sub()
caller.Value = "Done!!!"
End Sub)
End Sub)
workerThread.Start()
Return "Doing it..."
End Function
End Module
I have a user interface which generates the Events. So I have the event for example "ButtonPressed" with the arguments.
On event I want to fire time-consuming function "GenerateTableData". Also I want not to block the interface so this function should be on background thread.
After this I can pass the invocation back to the main thread and populate columns.
But if the user presses two times on the Button I don't want to create two threads. Instead I want to interrupt the privious one or waits until it's finished and immediately start another (separate buttons fills table with separate data and we need to show result only from the last one pressed).
And I am stuck with that option. All what seems working to me is casting backgroundworker on each event but I can't prevent it from execution two or more times and can't queued further events.
Please give me an example of solution of this task, I think it should be pretty common.
Here is some pseudocode:
void Button1Pressed(args)
{
DoWork(1);
}
void Button2Pressed(args)
{
DoWork(2);
}
void DoWork(int i)
{
BackGroundWorker bg=new BackGroundWorker();
bg.DoWork+= (object sender, DoWorkEventArgs e) => {e.result=GenerateTable(i)};
bg.RunWorkerCompleted+= (object sender, RunWorkerCompletedEventArgs e) =>{InvokeOnMainThread(()=>{PopulateColumns(e.result)})};
bg.RunWorkerAsync();
}
void PopulateColumns(data)
{
myTable.PopulateWithData(data);
}
The typical way to do this, is:
for each event type, that should be serialized, have a queue
Raising an event is queuing the event and kicking the queue (see below)
Wrap your worker in a method, that after finishing the task
resets a "worker is running" flag (no locking needed)
kicks the queue again
By "Kicking the queue" I mean
Check the "worker is running" flag, if it is set, do nothing (the ending worker will re-kick)
Try to dequeue from the locked queue, if it was empty, unlock and do nothing
So we have work to do: Before unlocking the queue, set the "worker is running" flag
How can you make a background web request and then update the UI, but have all the code that does the web requesting/parsing in a separate class so you can use it in multiple places? I thought I could use the classes methods as event handlers for a BackgroundWorker class, like
APIHelper mHelper = new APIHelper("http://example.com?foo=bar");
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork +=new DoWorkEventHandler(mHelper.GetResponse);
bw.RunWorkerCompleted +=new RunWorkerCompletedEventHandler(mHelper.HandleResponse);
bw.RunWorkerAsync();
where APIHelper has the method
public void GetResponse(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = (BackgroundWorker) sender;
WebRequest request = HttpWebRequest.Create(this.URL);
IAsyncResult result = (IAsyncResult)
request.BeginGetResponse(ResponseCallback, request);
}
but then I don't know how to access the worker thread from ResponseCallback and, anyway, HandleResponse gets called first (obviously). (I tried putting in result.AsyncWaitHandle.WaitOne(); but I get a NotSupportedException error.) Yet I can't work out how to make the web request call synchronously. I'm clearly trying to go about this the wrong way, but I have no idea what the right way is.
ETA:
My aim is to be able to go:
user clicks (a) button(s) (on various pages)
a "working" message is displayed on the UI thread (and then input is blocked)
in a background thread my APIHelper class makes the relevant API call, gets the response, and passes it back to the UI thread; I only seem to be able to do this by starting another thread and waiting for that to return, because there's no synchronous web requests
the UI thread updates with the returned message (and input continues as before)
I can do the first two bits, and if I have the response, I can do the last bits, but I can't work out how to do the middle bit. Hopefully that made it clearer!
It took me several tried before I found there is a Dispatcher.
During the BackgroundWorker's dowork and complete methods you can call:
this.Dispatcher.BeginInvoke(() =>
{
// UPDATE UI BITS
});
I think the Dispatcher is only available in the view. So I'm not sure if the methods can exist outside of the xaml.cs
Put whatever you want to update in your UI; when updating an ObservableCollection you must do the update of you items in the Dispatcher.BeginInvoke too
This link might be a good read too:
http://www.windowsphonegeek.com/articles/All-about-Splash-Screens-in-WP7-ndash-Creating-animated-Splash-Screen
Update to assist notes
This is just a rough idea mind you...
bw.DoWork +=new DoWorkEventHandler(DoWork);
bw.RunWorkerCompleted +=new RunWorkerCompletedEventHandler(Complete)
// At least I think the EA is DoWork....
public void DoWork(object sender, DoWorkEventArgs e)
{
mHelper.GetResponse();
this.Dispatcher.BeginInvoke(() =>
{
UIObject.Visibility Collapse.
});
// Wait and do work with response.
});
}
public void Complete(object sender, RunWorkerCompleteEventArgs e)
{
this.Dispatcher.BeginInvoke(() =>
{
UIObject.Visible ....
});
}
I'd put all this logic in a viewmodel that the viewmodel of each page inherits from.
Have the pages bind to properties on the viewmodel (such as ShowLoading, etc.) which the model updates appropriately. i.e. before making the webrequest and in the callback.
As you won't be running the viewmodel code in the UI thread you also wouldn't need to run in a separate BackgroundWorker and you'll be able to access the properties of the viewmodel without issue.
It might be useful if you use a helper class that I have developed for WebDownload purposes during WP7 development.
I'm using it in 2-3 WP7 apps and no problem so far. Give it a go to see if it helps. You can get the class from the my blog linked bellow:
http://www.manorey.net/mohblog/?p=17#content
[NOTE] When working with this class you don't need to run anything in a background worker or new thread; it handles it all asynchronously.
Im working on a Windows Service in which I would like to have two threads. One thread should look for updates (in a RSS feed) and insert rows into a DB when updates is found.
When updates are found I would like to send notification via another thread, that accesses the DB, gets the messages and the recipients and then sends notifications.
Perhaps the best practice isn't to use two threads. Should I have db-connections in both threads?
Could anyone provide me with tips how to solve this?
The major reason to make an application or service multithreaded is to perform database or other background operations without blocking (i.e. hanging) a presentation element like a Windows form. If your service depends on very rapid polling or expects db inserts to take a very long time, it might make sense to use two threads. But I can't imagine that either would be the case in your scenario.
If you do decide to make your service multithreaded, the two major classes in C# that you want to look into are BackgroundWorker and ThreadPool. If you want to do multiple concurrent db inserts (for example, if you want to execute an insert for each of multiple RSS feeds polled at the same time), you should use a ThreadPool. Otherwise, use a BackgroundWorker.
Typically, you'd have a db access class that would have a method to insert a row. That method would create a background worker, add DoWork handler to some static method in that db access class to the background worker, then call DoWorkAsync. You should only have db connection settings in that one class in order to make maintaining the code easier. For example:
public static class DbAccess
{
public void InsertRow(SomeObject entity)
{
BackgroundWorker bg = new BackgroundWorker();
bg.DoWork += InsertRow_DoWork;
bg.RunWorkerCompleted += InsertRow_RunWorkerCompleted;
bg.RunWorkerAsync(entity);
}
private void InsertRow_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bg = sender as BackgroundWorker;
SomeObject entity = e.Argument as SomeObject;
// insert db access here
}
private void InsertRow_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// send notifications
// alternatively, pass the InsertRow method a
// delegate to a method in the calling class that will notify
}
}
Here is my problem , I have created a SortableCollection : ObservableCollection
and added a sort method (sort colors).
When I sort The collection with the principal Thread , it works every thing is fine and works
But When I try to sort this customCollection by using an item in the collection I have an expetion : (The calling thread cannot access this object because a different thread owns it).
I have looked in web and I found several solution , One Solution
This type of solution put the collection multithread for insertion , removing moving operation.
But not for the custom sort.
Thanks for help,
WPF classes have thread affinity. What this means is that all changes to those objects must be in the same thread where they were created. It truly is difficult to create a user interface API that is thread-safe, so Microsoft chose to keep it singlethreaded and force run-time checking to make sure of it.
That said, there are a few options you have to perform your sort in a background thread, and then apply it in the UI thread. The first option is to copy your SortableCollection into a plain old List or Array and perform the sort in the background. Once the background thread is complete, you use a Dispatcher to execute code in the UI thread. Every UI element in WPF extends System.Windows.Threading.DispatcherObject and most extend System.Windows.Freezable. The DispatcherObject is where you get the Dispatcher to execute code in the UI thread.
Logically, the execution would be something like this:
public void BackgroundSort()
{
List<T> items = new List<T>(this.ToArray());
BackgroundSortDelegate del = Sort;
del.BeginInvoke(SortCompleted, del);
}
private void SortCompleted(IAsyncResult result)
{
BackgroundSortDelegate del = result.AsyncState as BackgroundSortDelegate;
List<T> items = del.EndInvoke(result);
this.Dispatcher.Invoke(()=>{this.Collection = items;});
}
The short explanation of what happened is that the background worker/delegate is using a copy of the items in this list. Once the sort is complete, we are calling the Dispatcher object and invoking an action. In that action we are assigning the new sorted list back to our object.
The key to assigning the result of any background work within the UI thread is to use the UI's Dispatcher object. There's actually probably a half dozen ways to invoke a background worker in C#, but the approach to get your work in a background thread into the UI thread is the same.