Consider the below code:
public void MyMethod()
{
bool flag=true;
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (x, y) =>
{
//time consuming task
if (flag)
{
//do something
}
};
worker.RunWorkerCompleted += (x, y) =>
{
if (flag)
{
//do something
}
};
worker.RunWorkerAsync();
}
Perhaps a stupid question, but as I can understand, after runworkerasync call, the dowork event is raised which runs its method on a different thread. Is checking the value of the local variable flag safe inside the dowork eventhandler since I feel the code exits MyMethod after calling worker.RunWorkerAsync?
There's no problem with flag here because of a concept called Closures. However, especially with threads this can be dangerous (use your favourite search engine).
Depending on your definition of 'safe', it is possible to check the local variable flag within DoWork as it remains in scope for that method. Having said that it may not necessarily be thread safe.
Related
Issue
I am streaming my camera out and want it to run on a separate thread as my UI is freezing. If I start a Thread on the first method call, does the methods inside that method go into the new thread or the old thread?
This is my setup at the moment.
Code
When the user clicks 'Start Stream':
Thread thread = new Thread(new ThreadStart(StartNewStream));
thread.Name = "streammm";
thread.Start();
This calls 'StartNewStream' method which calls other methods:
cam.OnSampleAvailable += (s, e) =>
{
lock (BusyLock)
rtspRecord.PushVideo(e.Sample);
};
win.OnSamplesAvailable += (s, e) =>
{
lock (BusyLock)
rtspRecord.PushAudio(e.Samples);
};
Do the methods PushVideo and PushAudio get called in the UI thread or the newly created thread?
If I go into the PushVideo method and put the code:
Thread TR = Thread.CurrentThread;
string _name = TR.name;
The name is now null?
Anyone help on what I am doing wrong?
Whichever thread invokes the OnSampleAvailable event or delegate will also execute its handlers. It does not matter which thread assigns the handlers.
You must understand what your code actually does:
cam.OnSampleAvailable += (s, e) =>
{
lock (BusyLock)
rtspRecord.PushVideo(e.Sample);
};
This does not call anything at first. It only assigns an anonymous method (s, e) => { ... } as a handler to the event cam.OnSampleAvailable.
The handler is not called here. The assignment completes and as the end of your StartNewStream method is reached, your new thread ends. Then, much later, there may be samples available on your cam. Whichever thread is responsible (we do not know) will invoke the cam.OnSampleAvailable event, and the handler (the anonymous method (s, e) => { ... } you assigned earlier) will be executed by that unknown thread.
It depends on the implementation of cam and win. Likey either those two events are running on their own thread pool thread or they may run on the UI thread if they are written in a way that knows how to capture the OperationContext
To update the UI from an other thread you need to call the BeginInvoke method of the dispatcher. Before you invoke you method you can check whether the calling thread is associated with the dispatcher.
For my example I have 2 ways to update a textbox; by clicking a button and by elapsing a timer. The Code:
using System;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
private int i = 0;
private TextBlock myText = new TextBlock();
private Button myButton = new Button();
private Timer timer = new Timer(2 * 1000);
private StackPanel panel = new StackPanel();
public MainWindow()
{
InitializeComponent();
myButton.Content = "Click";
panel.Children.Add(myText);
panel.Children.Add(myButton);
this.AddChild(panel);
myButton.Click += (_, __) => IncrementAndShowCounter();
timer.Elapsed += (_, __) => IncrementAndShowCounter();
timer.Start();
}
private void IncrementAndShowCounter()
{
i++;
if (this.Dispatcher.CheckAccess())
{
myText.Text = i.ToString();
}
else
{
this.Dispatcher.BeginInvoke((Action)(() =>
{
myText.Text = i.ToString();
}));
}
}
}
}
When I don't CheckAccess() and just always execute the BeginInvoke everything works fine.
So my question is why not always use the BeginInvoke and skip the CheckAccess?
So my question is why not always use the BeginInvoke and skip the
CheckAccess?
That's exactly what you should do most of the time if invoking is required (i.e. you are touching a control owned by another thread). If invoking is not required then you should skip both of them.
Using CheckAccess implies that your code doesn't know or doesn't want to assume that it will run on the "correct" thread. There are two main reasons for this: genericity (your code is in a library and you can't predict how it will be used) and convenience (you want only one method to take care of both cases, or you want the freedom to change the mode of operation without breaking the program).
Your example falls in the second category: the same method services both modes of operation. In this case you have three possible options:
Always invoke without CheckAccess.
This is going to give you a performance hit (a negligible one here), and it will also make readers of the code assume that the method is only called from worker threads. Since the only benefit is that you will be writing a little less code, this is the worst option.
Keep everything as it is.
Since IncrementAndShowCounter is called from both UI and worker threads, making it adapt to the situation lets you move on to other problems. This is simple and good; it's also the best you can do when writing library code (no assumptions allowed).
Never invoke from within the method, do it from outside as required.
This is the best option on technical merit: since you know the context in which the method will be called, arrange for the invocation to happen outside it. This way the method is not tied to any specific thread and you don't get unnecessary performance penalties.
Here's example code for the third option:
private void IncrementAndShowCounter()
{
i++;
myText.Text = i.ToString();
}
myButton.Click += (_, __) => IncrementAndShowCounter();
timer.Elapsed += (_, __) => Dispatcher.BeginInvoke(IncrementAndShowCounter);
If you 100% sure that the calling thread is UI thread - you can use the "DO" method directly.
If you 100% sure that the calling thread is not UI thread, but the operation should be done on the UI thread, you just call the BeginInvoke
....
// 100% I'm sure the Click handler will be invoked on UI thread
myButton.Click += (_, __) => IncrementAndShowCounter();
// here I'm not sure
timer.Elapsed += (_, __) => Dispatcher.BeginInvoke(IncrementAndShowCounter);
// 100% not UI thred here:
Task.Factory.StartNew(() => Dispatcher.BeginInvoke(IncrementAndShowCounter), TaskScheduler.Default)
private void IncrementAndShowCounter()
{
i++;
myText.Text = i.ToString();
}
I want to use BackgroundWorker in my application. And I've learned, that when I want to do this:
buttonStart.Enabled = false;
in main thread, with another thread I should do it like this:
if (buttonStart.InvokeRequired) { buttonStart.Invoke(new Action(() => buttonStart.Enabled = false)); }
else buttonStart.Enabled = false;
But when it goes to comparision operations:
if(tabControlDbSwitch.SelectedIndex == 0)
it doesn't works.
So, here is my question:
if ((!tabControlDbSwitch.InvokeRequired && tabControlDbSwitch.SelectedIndex == 0) ||
(tabControlDbSwitch.InvokeRequired && /*What should I write here?*/))
And maybe you've got some hints for me, 'cause I'm totally newbie in multi threading, but I want to learn it as fast as possible.
I.e. I've heard that sometimes it will be better to use BeginInvoke than Invoke, but I don't know why and when.
CheckSelection is the function that you invoke from the function where this if code was return
public void CheckSelection()
{
if (tabControlDbSwitch.InvokeRequired)
{
tabControlDbSwitch.Invoke(new Action(() => { CheckTabSelection(); }));
}
else
CheckTabSelection();
}
public void CheckTabSelection()
{
if (tabControlDbSwitch.SelectedIndex == 0)
{
// Do my work .....
}
}
You said you have heard that sometimes it will be better to use BeginInvoke than Invoke, but I don't know why and when. invoke and begin invoke are of two types delegate and control. In your example you are using Contol.Invoke
Delegate.Invoke: Executes synchronously, on the same thread.
Delegate.BeginInvoke: Executes asynchronously, on a threadpool thread means the function that is invoked in begin invoke will be executed on a new thread from a thread pool and you can continue doing your operation on same thread (Parallel execution).
Control.Invoke: Executes on the UI thread, but calling thread will wait for completion of the invoked function before continuing.
Control.BeginInvoke: Executes on the UI thread, and calling thread will not wait for completion of invoked function.
Yes it is advisable that we use Control.BeginInvoke rather then Control.Invoke as you don't have to worry about deadlocks.
For example, if you remove the code
if(tabControlDbSwitch.InvokeRequired)
and always use
tabControlDbSwitch.Invoke(new Action(() => { CheckTabSelection(); }));
and in some case this function is invoked from UI main thread then your code will hang and result in deadlock.
Here's another approach that actually allows the Invoke() to RETURN a value.
This way your code flows a little better:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
if (GetSelectedIndex(this.tabControlDbSwitch) == 0)
{
Console.WriteLine("Success!");
}
}
private delegate int ReturnSelectedIndex(TabControl tb);
private int GetSelectedIndex(TabControl tb)
{
if (tb.InvokeRequired)
{
return (int)tb.Invoke(new ReturnSelectedIndex(GetSelectedIndex), new Object[] { tb });
}
else
{
return tb.SelectedIndex;
}
}
I have a project here and it has set by default that the actions occur by MouseEnter event. I mean, opening a Window, closing, returning, whatever, happens only by the MouseEnter event.
I was requested to make the event fire only after 3 seconds. That means that the user will place the mouse on the control and only after 3 seconds the event must happen for all the controls in the window.
So, I thought about a global timer or something alike, that will return false untill the timer reaches 3... I think that's the way...
Geez, does anybody knows how can I make such thing?
Thanks!!
You can define a class that will expose a DelayedExecute method that receives an action to execute and creates timers as needed for the delayed execution. It would look something like this:
public static class DelayedExecutionService
{
// We keep a static list of timers because if we only declare the timers
// in the scope of the method, they might be garbage collected prematurely.
private static IList<DispatcherTimer> timers = new List<DispatcherTimer>();
public static void DelayedExecute(Action action, int delay = 3)
{
var dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
// Add the timer to the list to avoid it being garbage collected
// after we exit the scope of the method.
timers.Add(dispatcherTimer);
EventHandler handler = null;
handler = (sender, e) =>
{
// Stop the timer so it won't keep executing every X seconds
// and also avoid keeping the handler in memory.
dispatcherTimer.Tick -= handler;
dispatcherTimer.Stop();
// The timer is no longer used and shouldn't be kept in memory.
timers.Remove(dispatcherTimer);
// Perform the action.
action();
};
dispatcherTimer.Tick += handler;
dispatcherTimer.Interval = TimeSpan.FromSeconds(delay);
dispatcherTimer.Start();
}
}
Then you can call it like this:
DelayedExecutionService.DelayedExecute(() => MessageBox.Show("Hello!"));
or
DelayedExecutionService.DelayedExecute(() =>
{
DoSomething();
DoSomethingElse();
});
I just wanted to add a simpler solution:
public static void DelayedExecute(Action action, int delay = 3000)
{
Task.Factory.StartNew(() =>
{
Thread.Sleep(delay);
action();
}
}
Then use it just like in this other answer
Monitor moni = new Monitor();
Thread t = new Thread(() => moni.CurrUsage(nics,200));
t.Start();
I start a thread named 't' inside the 'Form1_Load' function. I have added a button. When click on that button the thread 't' should stop executing and create a new thread with these parameters.
Monitor moni = new Monitor();
Thread t = new Thread(() => moni.CurrUsage(nics,950));
t.Start();
I know in the form_load event i can use the
t.Abort();
By making t a member of the form, you can reference it later on in the button-click event handler.
Graceful Abort.
Although t.Abort() gets the job done, you might be left with half-processed data in the thread t. You can catch the ThreadAbortException in thread t to gracefully end processing.
Beware of overlap.
The second problem is that your thread might not have aborted yet while your new thread has started already. You can prevent that by calling t.Join() after calling t.Abort().
Hope this helps.
Make Thread t a private member of your form.
public partial class MainForm : Form
{
private Thread t;
}
One way is to make Thread t a global variable (place outside of Form_Load). Then it can be accessed and modified from any method in that class.
To instantiate the thread, use t = new Thread(.....
Before aborting the thread, make sure it is not null.
You need to make the Thread object accessable in both places that you need to access it.
In this case, making it a private varaible would work.
e.g.
public class MyClass
{
private Thread MyThread
{
get;
set;
}
private void myfunc1()
{
MyThread = new Thread(() => moni.CurrUsage(nics,200));
MyThread.Start();
}
private void myfunc2()
{
MyThread.Abort();
// I really need to wait until this thread has stopped...
MyThread.Join();
}
}
Adding to the already given answers:
Note that .Join() will block your current (UI) thread, leaving your application unresponsive to the user.
Just as another take: avoid using .Abort() by using a flag in your Monitor class to exit the task you are doing if possible. You can then still wait for .Join(), but you have full control of the state in the background thread.
public class Monitor
{
private bool _cancel = false;
public void Cancel()
{
_cancel = true;
}
public void CurrUsage(Nics nics, int n)
{
_cancel = false;
// ...
while (!_cancel)
{
// do some stuff
}
}
}
in your Form
private Monitor _monitor { get; set; }
private Thread _t;
public void Button_Click(...)
{
_monitor.Cancel()
_t.Join() // will return as your background thread has finished cleanly
_t = new Thread(() => _monitor.CurrUsage(nics,950));
t.Start();
}
As others have pointed out, all you need in order to call Abort is a reference to the thread (just like any other object in .NET).
However
You should seriously consider rethinking this approach. In general, calling Abort is discouraged, as it does not give the target thread sufficient opportunity to reach a stopping point. While it's sometimes appropriate (or the only option), it's almost always a better idea to ask the target thread to stop (usually through a volatile bool rather than forcing it like this.
For example,
public class ThreadClass
{
private volatile bool stopRequested;
private Thread thread;
public void Start()
{
stopRequested = false;
thread = new Thread(ThreadMethod);
thread.Start();
}
public void Stop()
{
stopRequested = true;
if(!thread.Join(5000)) thread.Abort(); // forcefully abort if not
// completed within 5 seconds
}
private void ThreadMethod()
{
}
}
Your code then goes into ThreadMethod. Within the method, periodically check the value of stopRequested. If it's true, perform whatever cleanup is necessary (if any) and gracefully return out of the thread. If the content is a loop, the general practice is to place the check at the start of the loop (assuming that the loop is sufficiently tight) and exit early if the value is true. The exact placement is really dependent upon the code, but the general idea is that it should be checked often enough to make the thread exit fairly quickly after it gets set, regardless of when that happens.