BeginInvoke on ObservableCollection not immediate - c#

In my code I subscribe to an event that happens on a different thread. Every time this event happens, I receive an string that is posted to the observable collection:
Dispatcher currentDispatcher = Dispatcher.CurrentDispatcher;
var SerialLog = new ObservableCollection<string>();
private void hitStation_RawCommandSent(object sender, StringEventArgs e)
{
string command = e.Value.Replace("\r\n", "");
Action dispatchAction = () => SerialLog.Add(command);
currentDispatcher.BeginInvoke(dispatchAction, DispatcherPriority.Render);
}
The code below is in my view model (could be in the code behind, it doesn't matter in this case). When I call "hitstation.PrepareHit", the event above gets called a couple times, then I wait and call "hitStation.HitBall", and the event above gets called a couple more times.
private void HitBall()
{
try
{
try
{
Mouse.OverrideCursor = Cursors.Wait;
//prepare hit
hitStation.PrepareHit(hitSpeed);
Thread.Wait(1000);
PlayWarning();
//hit
hitStation.HitBall(hitSpeed);
}
catch (TimeoutException ex)
{
MessageBox.Show("Timeout hitting ball: " + ex.Message);
}
}
finally
{
Mouse.OverrideCursor = null;
}
}
The problem I'm having is that the ListBox that is bound to my SerialLog gets updated only when the HitBall method finishes. I was expecting seeing a bunch of updates from the PrepareHit, a pause and then a bunch more updates from the HitBall.
I've tried a couple of DispatcherPriority arguments, but they don't seem to have any effect.

I think you are blocking yourself.
The UI Thread is waiting at Thread.Wait, BeginInvoke sends the action to the dipatcher, however the UI Thread is busy waiting. That is why UI updates only get done after HitBall finishes, that is, when the UI Thread finishes processing.
To get around this, you should start the HitBall method's code in another thread, freeing the UI:
private void HitBall()
{
try {
Mouse.OverrideCursor = Cursors.Wait;
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
Action hitOperations = () =>
{
hitStation.PrepareHit(hitSpeed);
Thread.Wait(1000);
//Only needed if PlayWarning needs access to UI Thread
dispatcher.Invoke(() => PlayWarning());
hitStation.HitBall(hitSpeed);
dispatcher.Invoke(() => Mouse.OverrideCursor = null);
};
//Free the UI from work, start operations in a background thread
hitOperations.BeginInvoke(null, null);
}
catch (TimeoutException ex)
{
MessageBox.Show("Timeout hitting ball: " + ex.Message);
}
}
Also if the intended use of Thread.Wait(1000) was to wait for events to refresh the UI, with this implementation it is no longer needed.

Could it be something as simple as needing to raise the PropertyChanged event on your ViewModel?

You will probably not see updates from PrepareHit unless there is a context switch and there is no guarantee when context switch will occur (unless you block your current thread and that would increase the probability that a context switch will occur).
As iCe mentioned if you're doing this on the UI thread, then you might be blocking your UI. Does your UI block/freeze when you call Thread.Wait? If it doesn't then proceed reading below:
Update:
I can't think of anything that would not compromise concurrency... without compromising concurrency you could try to increase the priority of BeginInvoke: http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcherpriority.aspx
currentDispatcher.BeginInvoke(dispatchAction, DispatcherPriority.Send);
By the way, it looks like Render priority is lower than Normal priority:
Render The enumeration value is 7.
Operations processed at the same
priority as rendering.
DataBind The
enumeration value is 8. Operations are
processed at the same priority as data
binding.
Normal The enumeration value
is 9. Operations are processed at
normal priority. This is the typical
application priority.
Send The
enumeration value is 10. Operations
are processed before other
asynchronous operations. This is the
highest priority.

Related

C# how to get a object back from a system.timer and use it in the calling tread

I am trying to have a system.timer calculate a object and return it to the calling tread in C#. If I calculate it the main trad then i get the object, but if I try to calculate the same in a system.timer I do not get any value back.
How to return a object from a system.timer an use it in the main tread?
public MainWindow()
{
Timer execute = new Timer();
execute.Interval = 5000;
execute.Elapsed += UpdatePending;
execute.Start();
InitializeComponent();
}
private void UpdatePending(Object source, System.Timers.ElapsedEventArgs e)
{
DataTable pending = new Repository().GetPending();
if (pending?.Rows.Count > 0)
{
dataGrid_Pending.DataContext = pending;
}
}
The dataGrid_Pending is not updating when I do this, but it is if I run the code in the main tread:
DataTable pending = new Repository().GetPending();
if (pending?.Rows.Count > 0)
{
dataGrid_Pending.DataContext = pending;
}
I made this Helper Class to run things to the UI Thread for my WPF Application
public static class InvokeUI
{
/// <summary>
/// Execute an Action in the Appropriate UI Thread
/// <para>Will Invoke the UI if you are not already in the Appropriate UI Thread</para>
/// <para>Runs Synchronously</para>
/// </summary>
/// <param name="action"></param>
public static void CheckAccess(Action action)
{
try
{
Dispatcher dispatcher = Application.Current.Dispatcher;
if (dispatcher.CheckAccess())
{
action();
return;
}
dispatcher.Invoke(delegate
{
try
{
action();
}
catch (Exception ex)
{
// Log This Error
}
}, DispatcherPriority.Render);
}
catch
{
// The Dispatcher might throw here during closing and after the UI has already been disposed
}
}
}
You use it like this
InvokeUI.CheckAccess(() =>
{
dataGrid_Pending.DataContext = pending;
// Your UI Update
});
This is option number 4 from the answer JonasH provided.
How to return a object from a system.timer an use it in the main tread?
You need to politely ask the UI thread to run some code on your behalf. There are many ways to do this
SynchronizationContext.Post
Control.Invoke
TaskScheduler.FromCurrentSynchronizationContext
Dispatcher.Invoke
Some of these require you to save an object to use in your timer event. If you are using WPF the dispatcher is probably easiest to use, since you can use the static Application.Current.Dispatcher to get it:
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() => DataContext = pending));
Note that whenever you are dealing with multiple threads, and timers.timer will by default invoke the event handler on a thread pool thread, you cannot access the UI, and you have to ensure the code is thread safe.
You might consider using a DispatcherTimer instead, since this will invoke events on the UI thread, removing the problem. This is the best approach if your event handler is fairly fast, say ~50ms or so.
If it is slower it might be more useful to run the event on a background thread, but then you need to worry about what will happen if one event handler does not finish before the next tick occur, in addition to any thread safety concerns.

Updating a Control's property (label.Text) from another thread

In my windows application I want to update a label's Text property from another thread when some button is clicked:
Here is the code of my button click event handler:
StatusLabel.Text = "Started";
Task.Factory
.StartNew(() =>
{
… // long-running code
StatusLabel.Text = "Done";
}, CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext())
.ContinueWith(tsk =>
{
MessageBox.Show("something broke");
var flattened = tsk.Exception.Flatten();
// note: Don't actually handle exceptions this way, m'kay?
flattened.Handle(ex => { MessageBox.Show("Error:" + ex.Message); return true; });
}, TaskContinuationOptions.OnlyOnFaulted);
When I click the button the above code is executed. I am not seeing the StatusLabel.Text = "Started"; at once. It seems it waits for // long-running code and then it is executed.
What I want is to see the "Started" in the label as soon as the button is clicked, and when the long-running task is done, I want to see "Done" on the label.
There are two reasons why this is happening.
First, you are telling the task to run on the GUI thread, by specifying TaskScheduler.FromCurrentSynchronizationContext() as a parameter. This means that your processing is not happening on a background thread, but on a GUI thread. Second is that changing a control's property only invalidates it, meaning that it will only be redrawn once the GUI thread has done processing other jobs.
In other words, you set the value to "Started" (and the label only invalidates itself), and then immediately queue the "background" task to the GUI thread, keeping it busy from painting controls. Your form will appear "hanged" during this time, and you will probably be unable to even move it around.
The simplest way to do a background job in Windows Forms is to use a BackgroundWorker. If you, however, really want to use a Task, then use the simple task factory method which doesn't accept a sync context, and then make sure that all UI interactions from that background thread are invoked on a GUI thread:
StatusLabel.Text = "Started";
// this is the simple Task.Factory.StartNew(Action) overload
Task.Factory.StartNew(() =>
{
// do some lengthy processing
Thread.Sleep(1000);
// when done, invoke the update on a gui thread
StatusLabel.Invoke(new Action(() => StatusLabel.Text = "Done"));
});
Alternatively, you may simplify the whole thing by moving GUI thread sync logic into a separate method:
// this method can be invoked from any thread
private void UpdateStatusLabel(string msg)
{
if (StatusLabel.InvokeRequired)
{
StatusLabel.Invoke(new Action<string>(UpdateStatusLabel), msg);
return;
}
StatusLabel.Text = msg;
}
And then simply call the method from wherever you wish:
private void button1_Click(object sender, EventArgs e)
{
UpdateStatusLabel("Started");
Task.Factory.StartNew(() =>
{
// do some lengthy processing
Thread.Sleep(10000);
// no need to invoke here
UpdateStatusLabel("Done");
});
}
If I understand, the button click happens in the UI thread, so no problem to set the label text to "Started" from there. Then you start the long running code from a different thread. Call Invoke method from a different thread to update UI elements after the long running code finishes:
Invoke((Action) (() => StatusLabel.Text = "Done"));
private async void Button_Clicked(object sender, EventArgs e)
{
Device.BeginInvokeOnMainThread(() =>
{
// UI updates ( label text change, button enable/disable )
});
await task;
await Task.Run(()=> {
// Synchronous methods
});
}
These can be arranged any how based on requirements.
All run serially. Like here first UI update then task completes and then other synchronous methods will be run.
If those synchronous methods have UI updates again the same way has to be followed like this method. Since those updates are inside a sync method which is called by this async method. All connected synchronous methods should be treated like async method only without "await". Because they are called from Task.Run of this method so they get converted to async method

Parallel.ForEach freezing on last loop [duplicate]

More newbie questions:
This code grabs a number of proxies from the list in the main window (I couldn't figure out how to make variables be available between different functions) and does a check on each one (simple httpwebrequest) and then adds them to a list called finishedProxies.
For some reason when I press the start button, the whole program hangs up. I was under the impression that Parallel creates separate threads for each action leaving the UI thread alone so that it's responsive?
private void start_Click(object sender, RoutedEventArgs e)
{
// Populate a list of proxies
List<string> proxies = new List<string>();
List<string> finishedProxies = new List<string>();
foreach (string proxy in proxiesList.Items)
{
proxies.Add(proxy);
}
Parallel.ForEach<string>(proxies, (i) =>
{
string checkResult;
checkResult = checkProxy(i);
finishedProxies.Add(checkResult);
// update ui
/*
status.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Normal,
new Action(
delegate()
{
status.Content = "hello" + checkResult;
}
)); */
// update ui finished
//Console.WriteLine("[{0}] F({1}) = {2}", Thread.CurrentThread.Name, i, CalculateFibonacciNumber(i));
});
}
I've tried using the code that's commented out to make changes to the UI inside the Parallel.Foreach and it makes the program freeze after the start button is pressed. It's worked for me before but I used Thread class.
How can I update the UI from inside the Parallel.Foreach and how do I make Parallel.Foreach work so that it doesn't make the UI freeze up while it's working?
Here's the whole code.
You must not start the parallel processing in your UI thread. See the example under the "Avoid Executing Parallel Loops on the UI Thread" header in this page.
Update: Or, you can simply create a new thread manuall and start the processing inside that as I see you have done. There's nothing wrong with that too.
Also, as Jim Mischel points out, you are accessing the lists from multiple threads at the same time, so there are race conditions there. Either substitute ConcurrentBag for List, or wrap the lists inside a lock statement each time you access them.
A good way to circumvent the problems of not being able to write to the UI thread when using Parallel statements is to use the Task Factory and delegates, see the following code, I used this to iterate over a series of files in a directory, and process them in a Parallel.ForEach loop, after each file is processed the UI thread is signaled and updated:
var files = GetFiles(directoryToScan);
tokenSource = new CancellationTokenSource();
CancellationToken ct = tokenSource.Token;
Task task = Task.Factory.StartNew(delegate
{
// Were we already canceled?
ct.ThrowIfCancellationRequested();
Parallel.ForEach(files, currentFile =>
{
// Poll on this property if you have to do
// other cleanup before throwing.
if (ct.IsCancellationRequested)
{
// Clean up here, then...
ct.ThrowIfCancellationRequested();
}
ProcessFile(directoryToScan, currentFile, directoryToOutput);
// Update calling thread's UI
BeginInvoke((Action)(() =>
{
WriteProgress(currentFile);
}));
});
}, tokenSource.Token); // Pass same token to StartNew.
task.ContinueWith((t) =>
BeginInvoke((Action)(() =>
{
SignalCompletion(sw);
}))
);
And the methods that do the actual UI changes:
void WriteProgress(string fileName)
{
progressBar.Visible = true;
lblResizeProgressAmount.Visible = true;
lblResizeProgress.Visible = true;
progressBar.Value += 1;
Interlocked.Increment(ref counter);
lblResizeProgressAmount.Text = counter.ToString();
ListViewItem lvi = new ListViewItem(fileName);
listView1.Items.Add(lvi);
listView1.FullRowSelect = true;
}
private void SignalCompletion(Stopwatch sw)
{
sw.Stop();
if (tokenSource.IsCancellationRequested)
{
InitializeFields();
lblFinished.Visible = true;
lblFinished.Text = String.Format("Processing was cancelled after {0}", sw.Elapsed.ToString());
}
else
{
lblFinished.Visible = true;
if (counter > 0)
{
lblFinished.Text = String.Format("Resized {0} images in {1}", counter, sw.Elapsed.ToString());
}
else
{
lblFinished.Text = "Nothing to resize";
}
}
}
Hope this helps!
If anyone's curious, I kinda figured it out but I'm not sure if that's good programming or any way to deal with the issue.
I created a new thread like so:
Thread t = new Thread(do_checks);
t.Start();
and put away all of the parallel stuff inside of do_checks().
Seems to be doing okay.
One problem with your code is that you're calling FinishedProxies.Add from multiple threads concurrently. That's going to cause a problem because List<T> isn't thread-safe. You'll need to protect it with a lock or some other synchronization primitive, or use a concurrent collection.
Whether that causes the UI lockup, I don't know. Without more information, it's hard to say. If the proxies list is very long and checkProxy doesn't take long to execute, then your tasks will all queue up behind that Invoke call. That's going to cause a whole bunch of pending UI updates. That will lock up the UI because the UI thread is busy servicing those queued requests.
This is what I think might be happening in your code-base.
Normal Scenario: You click on button. Do not use Parallel.Foreach loop. Use Dispatcher class and push the code to run on separate thread in background. Once the background thread is done processing, it will invoke the main UI thread for updating the UI. In this scenario, the background thread(invoked via Dispatcher) knows about the main UI thread, which it needs to callback. Or simply said the main UI thread has its own identity.
Using Parallel.Foreach loop: Once you invoke Paralle.Foreach loop, the framework uses the threadpool thread. ThreadPool threads are chosen randomly and the executing code should never make any assumption on the identity of the chosen thread. In the original code its very much possible that dispatcher thread invoked via Parallel.Foreach loop is not able to figure out the thread which it is associated with. When you use explicit thread, then it works fine because the explicit thread has its own identity which can be relied upon by the executing code.
Ideally if your main concern is all about keeping UI responsive, then you should first use the Dispatcher class to push the code in background thread and then in there use what ever logic you want to speedup the overall execution.
if you want to use parallel foreach in GUI control like button click etc
then put parallel foreach in Task.Factory.StartNew
like
private void start_Click(object sender, EventArgs e)
{
await Task.Factory.StartNew(() =>
Parallel.ForEach(YourArrayList, (ArraySingleValue) =>
{
Console.WriteLine("your background process code goes here for:"+ArraySingleValue);
})
);
}//func end
it will resolve freeze/stuck or hang issue

How to properly keep the UI updated while transferring packets in C#?

I have this form that spawns a new thread and starts listening and waiting for UDP packets in a loop. What I need is to keep the UI updated with the number of bytes received.
For that, I have setup an event which I'll raise as soon as a packet is received and pass the number of bytes received as an argument. Since I'm not running on the UI thread, I cannot simply update the UI directly. Here's what I'm currently doing:
private void EVENTHANDLER_UpdateTransferProgress(long receivedBytes) {
if(InvokeRequired) {
Invoke(new MethodInvoker(() => {
totalReceivedBytes += receivedBytes;
Label.Text = totalReceivedBytes.ToString("##,0");
}));
}
}
But this is still running on the same thread as the packet reception loop and it will not return to that loop - and wait for another packet - until this EVENTHANDLER_UpdateTransferProgress method returns.
My question is basically about the following line in the method above:
Label.Text = totalReceivedBytes.ToString("##,0");
Updating the UI like this slows down the packet reception. If I take that line off (or comment it), the packet reception will be much faster.
How can I possibly solve this issue? I think more threads is the key, but I'm not sure how to properly implement them in this situation... I'm using Windows Forms with .NET 2.0.
EDIT:
On my previous testing, the above seem to be true and it may actually be to some extent. But after a little more testing I realized the problem was on the whole Invoke(new MethodInvoker(() => { ... })); thing. When I remove that (the UI won't be updated of course) and leave EVENTHANDLER_UpdateTransferProgress but keep raising the event, the packet reception is much faster.
I tested receiving some file which took in average about ~1.5sec without calling Invoke() at all on the event handler. When I did call Invoke() in the event handler, even without updating any control in the UI or doing any operation (in other words, the anonymous method body was empty), it took much longer, around ~5.5sec. You can see it's a big difference.
Is there anyway to improve this?
The problem with your approach is that it updates the UI on every single packet. If you received 1000 packets every second, you would update the UI 1000 times every second! The monitor probably doesn't refresh more than 100 times per second, and nobody is going to be able to read it if it updates more than 10 times per second.
A better way to approach this problem is to put the totalReceivedBytes += receivedBytes; in the thread that handles the I/O and put a timer on the UI thread that executes Label.Text = totalReceivedBytes.ToString("##,0"); only a few times per second at most. When the transfer starts, start the timer; when the transfer stops, stop the timer.
Yes, there is a way to improve this.
The first is to use BeginInvoke instead of Invoke which will not wait for the invoke to return. You should also consider using another form in your method
private void EVENTHANDLER_UpdateTransferProgress(long receivedBytes) {
if(InvokeRequired) {
BeginInvoke(new Action<long>(EVENTHANDLER_UpdateTransferProgress),
receivedBytes));
return;
}
totalReceivedBytes += receivedBytes;
Label.Text = totalReceivedBytes.ToString("##,0");
}
So if you call this method from a method that does not require invoking, the update on the GUI is still performed.
Another option that you can do is break of a thread in your download thread. Something in the likes of
public event EventHandler<MonitorEventArgs> ReportProgress;
public void startSendingUpdates(MonitorEventArgs args) {
EventHandler<MonitorEventArgs> handler = ReportProgress;
if (handler == null) {
return;
}
ThreadPool.QueueUserWorkItem(delegate {
while (!args.Complete) {
handler(this, args);
Thread.Sleep(800);
}
});
}
public void download() {
MonitorEventArgs args = new MonitorEventArgs();
startSendingUpdates(args);
while (downloading) {
int read = downloadData(bytes);
args.BytesTransferred += read;
}
args.Complete = true;
}
public class MonitorEventArgs : EventArgs {
public bool Complete { get; set; }
public long BytesTransferred { get; set; }
}
The overhead of this is kind of small compared to the benefits. Your download thread is not affected by the updates to the GUI (at least not compared to waiting on the GUI to update). The downside is you are occupying a thread in the threadpool, but hey, that's what they're there for! And, the thread shuts down when it's done, since you set the complete flag. You don't need to lock when setting that either, since an extra run in the worker thread is unimportant in the context.
Have you tried using BeginInvoke instead of Invoke? BeginInvoke() is an asychronous call.
private void EVENTHANDLER_UpdateTransferProgress(long receivedBytes) {
if(InvokeRequired) {
BeginInvoke(new MethodInvoker(() => {
totalReceivedBytes += receivedBytes;
Label.Text = totalReceivedBytes.ToString("##,0");
}));
}
}

Dispatcher.Invoke from a new thread is locking my UI

i'm using wpf, there's a button on my ui.
when the user clicks it, i have a for loop that runs a new method, on a new thread using autoresetevent.
in that method on that new thread, i'm using a label, let's call it lblStatus. i want to update that label on this thread that's not on the ui. using wpf, i have to use Dispatcher.Invoke.
here's a sample of my code:
Thread thread= new Thread(StartLooking);
thread.Start();
_waitHandle.WaitOne();
private void StartLooking(object value)
{
if (lblStatus.Dispatcher.Thread == Thread.CurrentThread)
{
lblStatus.Content = "Scanning>...";
}
else
{
lblStatus.Dispatcher.Invoke(DispatcherPriority.Background, new Action(() => lblStatus.Content = "Scanning>>>>>"));
}
_waitHandle.Set();
}
the program just stops here. it doesn't change the content of the label, it returns to my ui, but blocks it.
i've tried
lblStatus.Dispatcher.Invoke(DispatcherPriority.Normal, new LblStatusThreadCheck(lblStatusThreadCheck), "Scanning...");
as well, but that isn't working also. any ideas?
The problem is that you're making it impossible for this to execute, since you're using Invoke.
Dispatcher.Invoke will not return until the UI thread processes. However, you've blocked the UI thread by calling _waitHandle.WaitOne();, and don't set the wait handle until AFTER this processes. The two effectively cause a dead lock.
If you switch this to use BeginInvoke instead, the UI will queue the element, the wait handle will set, THEN the label will update. It will work and not block, however.
Since the two previous posts already cover the problem in your code, just a suggestion: instead of
if (lblStatus.Dispatcher.Thread == Thread.CurrentThread)
try using
if (!lblStatus.CheckAccess())
It's cleaner and has the exact intent you want. Just read about it here.
You probably want to use BeginInvoke instead. Invoke will block the thread that called it until the UI thread has run the Action, and since you're setting the priority to Background, this could take some time.
Best solution I have found for .net 4.5+ is using SynchronizationContext Post
Example (Task.Run's can be as many as you want in parallel accessing UI):
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
var context = SynchronizationContext.Current;
Task.Run(() =>
{
var i = 0;
while (true)
{
context.Post((tmp) =>
{
uiText.Text = $"{i}";
}), this);
Thread.Sleep(1000);
i++;
}
});
}

Categories

Resources