I have an app that has several methods that take a long time to complete. I am using a backgroundworker to run these methods and keep my UI responsive. My methods look something like
public void DoSomething()
{
while( HaveMoreWork )
{
// do work
}
}
Now i want the UI to be able to cancel this at any time so I have changed my methods to take a Backgroundworker like so
public void DoSomething(Backgroundworker worker)
{
while( HaveMoreWork && !worker.CancelationPending )
{
// do work
}
}
My question is, is there a better way to do this. Seems like passing a Backgroundwoker as an argument to all these methods is a bit messy. What is best practice for this?
I am using global variable
private BackgroundWorker _bwSearch = new BackgroundWorker();
private void InitializeBackgroundWorker()
{
_bwSearch = new BackgroundWorker();
_bwSearch.WorkerSupportsCancellation = true;
_bwSearch.DoWork += bwSearch_DoWork;
_bwSearch.RunWorkerCompleted += bwSearch_RunWorkerCompleted;
}
when clicked on stop button
private void btnCancel_Click(object sender, EventArgs e)
{
_bwSearch.Abort();
}
Updated:
Also I am using this simple helper class that is inherited from BackgroundWorker
public class AbortableBackgroundWorker : BackgroundWorker
{
private Thread _workerThread;
protected override void OnDoWork(DoWorkEventArgs e)
{
_workerThread = Thread.CurrentThread;
try
{
base.OnDoWork(e);
}
catch (ThreadAbortException)
{
e.Cancel = true;
Thread.ResetAbort();
}
}
public void Abort()
{
if (_workerThread != null)
{
_workerThread.Abort();
_workerThread = null;
}
}
}
public class DoSomethingService
{
private volatile bool _stopped = false;
public void Start(object socketQueueObject)
{
while (!_stopped)
{
...
}
}
public void Stop()
{
_stopped = true;
}
}
...
var doSomethingService = DoSomethingService();
doSomethingService.Start();
...
doSomethingService.Stop();
Related
I'm writing a small Keylogger for some statistics about my typing.
The Keylogger works fine, but now i want to implement it to a wpf to have a better control.
public MainWindow()
{
InitializeComponent();
Thread ThreadLog = new Thread(Log);
Thread ThreadRefreshForm = new Thread(refreshForm);
Thread ThreadAutoSave = new Thread(AutoSave);
ThreadLog.Start();
ThreadRefreshForm.Start();
ThreadAutoSave.Start();
}
private void btn_ThreadLogStop_Click(object sender, RoutedEventArgs e)
{
if (ThreadLog.IsAlive == true)
{
ThreadLog.Abort();
}
This gives me an Error # ThreadLog.IsAlive. How can i solve the Problem?
Thanks for your help!!!!
You should declare your ThreadLog somewhere else and initialize it in the constructor, such that the method can access the ThreadLog:
private Thread ThreadLog;
public MainWindow()
{
InitializeComponent();
ThreadLog = new Thread(Log);
...
}
private void btn_ThreadLogStop_Click(object sender, RoutedEventArgs e)
{
if (ThreadLog.IsAlive == true)
{
ThreadLog.Abort();
}
Generally speaking the correct way how to end threads is like this
private volatile bool m_Stop;
public void ThreadLoop()
{
while(!m_Stop) {
// do some work
}
}
// starting
new Thread(ThreadLoop).Start();
// "force" end
m_Stop = true;
Or if you prefer tasks over threads (which I do):
public void ThreadLoop(CancellationToken token)
{
while(!token.IsCancellationRequested)
{
// do some work
}
}
var cancelation = new CancellationTokenSource();
// starting
new Task(() => ThreadLoop(cancelation.Token), cancelation.Token).Start();
// "force" end
cancelation.Cancel();
The example below functions fine, but I want to have the Complete event fire its event handlers in the UI thread. I don't want HasCompleted() to have to worry about checking if it's on the UI thread or not. Calls to HasCompleted() should always be invoked on the UI thread. How do I do this?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var game = new Game();
game.Complete += HasCompleted;
game.Load();
}
private void HasCompleted()
{
if (label1.InvokeRequired)
{
label1.BeginInvoke(new Action(() => label1.Text = "complete"));
}
else
{
label1.Text = "complete";
}
}
}
public class Game
{
public Game()
{
}
public event MethodInvoker Complete;
public void Load()
{
var task = new Task(new Action(() =>
{
Thread.Sleep(500);
OnComplete();
}));
task.Start();
}
private void OnComplete()
{
if (Complete != null)
{
Complete();
}
}
}
Capture the current synchronization context when you create the Game object and use that to marshal the event to the context that was current when the object was first created:
public class Game
{
private SynchronizationContext context;
public Game()
{
context = SynchronizationContext.Current ??
new SynchronizationContext();
}
public MethodInvoker Complete;
public void Load()
{
//...
}
private void OnComplete()
{
if (Complete != null)
{
context.Post(_ => Complete(), null);
}
}
}
I made a thread at load event like below:
Thread checkAlert = null;
bool isStop = false;
private void frmMain_Load(object sender, EventArgs e)
{
checkAlert = new Thread(CheckAlert);
checkAlert.Start();
}
void CheckAlert()
{
while (!isStop)
{
Thread.Sleep(60000);
//do work here
}
}
Is there any way to resume the checkAlert thread during it's sleep period?( Thread.Sleep(60000);)
I tried using Thread.Interrupt() but it flows a ThreadInterruptedException, how should I handle this exception? or is there any way to resume the thread?
Edited:
I need to wake up the thread before the "sleep" end because when the user wants to quit the program, the program will have to wait for some time before it really quits ( checkAlert is still running) Is there any way to improve this case?
Based on your comments what it looks like is you need to re-design how CheckAlert works so it does not use Sleep's at all. What you should be doing is using a Timer instead.
System.Timers.Timer timer = null;
public FrmMain()
{
InitializeComponent();
timer = new System.Timers.Timer(60000);
timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
//If you want OnTimedEvent to happen on the UI thread instead of a ThreadPool thread, uncomment the following line.
//timer.SynchronizingObject = this;
if(this.components == null)
this.components = new System.ComponentModel.Container();
//This makes it so when the form is disposed the timer will be disposed with it.
this.componets.Add(timer);
}
private void frmMain_Load(object sender, EventArgs e)
{
timer.Start();
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
//It is good practice not to do complicated logic in a event handler
// if we move the logic to its own method it is much easier to test (you are writing unit tests, right? ;) )
CheckAlert();
}
void CheckAlert()
{
//do work here
}
private void frmMain_Close(object sender, EventArgs e)
{
timer.Stop();
}
If you want the thread to exit automatically when your program quits, simply make it a background thread.
checkAlert = new Thread(CheckAlert);
checkAlert.IsBackground = true;
checkAlert.Start();
It looks to me like you're trying to create a thread which handles two types of events: do something and stop running.
Rather than using a shared variable (isStop) and some other technique to interrupt the thread in order to do work, you might want to use threading events (not to be confused high-level UI Event objects) to control your thread.
AutoResetEvent stop = new AutoResetEvent(false);
AutoResetEvent check = new AutoResetEvent(false);
private void CheckAlert() {
WaitHandle[] handles = new WaitHandle[] { stop, check };
for (;;) {
switch (AutoResetEvent.WaitAny(handles)) {
case 0:
return;
case 1:
// do work
break;
}
}
}
Calling check.Set() in your code will trigger the "do work" branch in the thread and stop.Set() will cause the thread to terminate gracefully.
Once your code has called stop.Set() to terminate the thread, it can call the thread's Join() method to wait until the thread terminates.
EDIT
I misunderstood the question. I will leave the code above in case anyone finds it useful.
If all you want to do is have a thread that performs a task once a minute and stop on demand, you can use the following code:
AutoResetEvent stop = new AutoResetEvent(false);
void CheckAlert() {
var time = new TimeSpan(0, 1, 0); // one minute
while (!stop.WaitOne(time)) {
// do work
}
}
private Thread checkThread;
private void frmMain_Load(object sender, EventArgs e) {
checkThread = new Thread(CheckAlert);
checkThread.Start();
}
private void frmMain_Close(object sender, EventArgs e) {
stop.Set(); // signal thread to stop
checkThread.Join(); // wait for thread to terminate
}
You can see an explanation on how to wake a sleeping thread here:
https://msdn.microsoft.com/en-us/library/tttdef8x%28v=vs.100%29.aspx
and this is a complete example (as you can see, Thread.Interrupt is the good choise... however you have to catch it to continue normal thread execution):
public class HVCSensor : HVCDevice, IDisposable
{
private Thread myThread;
private const int execute_timeout = ((10 + 10 + 6 + 3 + 15 + 15 + 1 + 1 + 15 + 10) * 1000);
private bool disposed = false;
private bool paused = false;
public delegate void HVCResultsHandler(HVC_RESULT res);
public event HVCResultsHandler HVCResultsArrived;
private void OnHVCResultsArrived(HVC_RESULT res)
{
if (HVCResultsArrived != null) {
HVCResultsArrived(res);
}
}
public HVCSensor() {
myThread = new Thread(new ThreadStart(this.execute));
}
private void execute(){
while (!disposed) {
if (!paused && this.IsConnected)
{
HVC_RESULT outRes;
byte status;
try
{
this.ExecuteEx(execute_timeout, activeDetections, imageAcquire, out outRes, out status);
OnHVCResultsArrived(outRes);
}
catch (Exception ex) {
}
}
else {
try
{
Thread.Sleep(1000);
}
catch (ThreadInterruptedException e)
{
}
}
}
}
public HVC_EXECUTION_IMAGE imageAcquire
{
get;
set;
}
public HVC_EXECUTION_FLAG activeDetections
{
get;
set;
}
public void startDetection() {
if(myThread.ThreadState==ThreadState.Unstarted)
myThread.Start();
}
public void pauseDetection() {
paused = true;
}
public void resumeDetection() {
paused = false;
if (myThread.ThreadState == ThreadState.WaitSleepJoin)
myThread.Interrupt();
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
disposed = true;
myThread.Interrupt();
}
}
This is my main form class and inside i have Stop button click event:
public partial class MainWin : Form
{
private Job job = new...
private void btnStop_Click(object sender, EventArgs e)
{
job.state = true;
}
}
When my stop button clicked i change my job class member from false to true and what i want to do is when this variable changed to true i want to access to specific method inside job class and do something.
public class Job
{
public bool state { get; set; }
private void processFile() // i want access to this method in order to change other class state
{
// do work
}
}
how can i do it ?
It's really hard to tell what you exactly mean, but one way to invoke a method when the property is set would be to expand the auto property out and do exactly that.
public class Job
{
private bool state;
public bool State
{
get { return this.state; }
set
{
this.state = value;
processFile();
}
private void processFile()
{
// do work
}
}
However, just guessing and seeing this little bit of code, you might want to redesign how you're doing things.
If really don't want to expose you private method, you can do something like this:
public class Job
{
private bool state;
public bool State
{
get
{
return state;
}
set
{
if (state != value)
{
state = value;
OnStateChanged();
}
}
}
private void OnStateChanged()
{
if (state) // or you could use enum for state
Run();
else
Stop();
}
private void Run()
{
// run
}
private void Stop()
{
// stop
}
}
But you should really consider creating public Job.Run method and leaving Job.State readonly. If you want the object to perform some operations, the methods will be more suitable for this.
Create the Job class like this:
public class Job
{
private bool _isRunning = false;
public bool IsRunning { get { return _isRunning; } }
public void StartProcessing()
{
if (_isRunning)
{
// TODO: warn?
return;
}
ProcessFile();
}
public void StopProcessing()
{
if (!_isRunning)
{
// TODO: warn?
return;
}
// TODO: stop processing
}
private void ProcessFile()
{
_isRunning = true;
// do your thing
_isRunning = false;
}
}
Then consume it like this:
public partial class MainWin : For
{
private Job _job = new Job();
private void StartButton_Click(object sender, EventArgs e)
{
if(!_job.IsRunning)
{
_job.StartProcessing();
}
}
private void StopButton_Click(object sender, EventArgs e)
{
if(_job.IsRunning)
{
_job.StopProcessing();
}
}
}
Thread safety left out as exercise.
I have an external library which has a method which performs a long running task on a background thread. When it's done it fires off a Completed event on the thread that kicked off the method (typically the UI thread). It looks like this:
public class Foo
{
public delegate void CompletedEventHandler(object sender, EventArgs e);
public event CompletedEventHandler Completed;
public void LongRunningTask()
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.RunWorkerAsync();
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(5000);
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (Completed != null)
Completed(this, EventArgs.Empty);
}
}
The code that calls this library looks like this:
private void button1_Click(object sender, EventArgs e)
{
Foo b = new Foo();
b.Completed += new Foo.CompletedEventHandler(b_Completed);
b.LongRunningTask();
Debug.WriteLine("It's all done");
}
void b_Completed(object sender, EventArgs e)
{
// do stuff
}
How do I unit test the call to .LongRunningTask given that it returns data in an event?
I'm not sure if I got it right. Do you want to check the external library if it fires the event? Or do you want to check that you do something particularly if the event is fired?
If it is the latter, I would use a mock for that. The problem is though, that your code seems to be hard to test, because you're doing logical stuff in the user interface. Try to write a "passive" view, and let a presenter do the magic. For example by using the Model View Presenter pattern http://msdn.microsoft.com/en-us/magazine/cc188690.aspx
The whole thing would then look like this.
The Model
public class Model : IModel
{
public event EventHandler<SampleEventArgs> Completed;
public void LongRunningTask()
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += this.bw_DoWork;
bw.RunWorkerCompleted += this.bw_RunWorkerCompleted;
bw.RunWorkerAsync();
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (this.Completed != null)
{
this.Completed(this, new SampleEventArgs {Data = "Test"});
}
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
System.Threading.Thread.Sleep(5000);
}
}
The View
public Form1()
{
InitializeComponent();
}
public event EventHandler Button1Clicked;
public void Update(string data)
{
this.label1.Text = data;
}
private void Button1Click(object sender, EventArgs e)
{
if (this.Button1Clicked != null)
{
this.Button1Clicked(this, EventArgs.Empty);
}
}
The Presenter
public class Presenter
{
private readonly IForm1 form1;
private readonly IModel model;
public Presenter(IForm1 form1, IModel model)
{
this.form1 = form1;
this.model = model;
this.form1.Button1Clicked += this.Form1Button1Clicked;
this.model.Completed += this.ModelCompleted;
}
private void ModelCompleted(object sender, SampleEventArgs e)
{
this.form1.Update(e.Data);
}
private void Form1Button1Clicked(object sender, EventArgs e)
{
this.model.LongRunningTask();
}
}
Somewhere you assemble it (e.g. in the Program class)
var form = new Form1();
var model = new Model();
var presenter = new Presenter(form, model);
Application.Run(form);
And then you can easily just test the presenter in an unit test. The part in the gui is now little enough to not be tested.
The possible test could look like this
[Test]
public void Test()
{
var form1Mock = new Mock<IForm1>();
var modelMock = new Mock<IModel>();
var presenter = new Presenter(form1Mock.Object, modelMock.Object);
modelMock.Setup(m => m.LongRunningTask()).Raises(m => m.Completed += null, new SampleEventArgs() { Data = "Some Data" });
form1Mock.Raise(f => f.Button1Clicked += null, EventArgs.Empty);
form1Mock.Verify(f => f.Update("Some Data"));
}
Well, I believe BackgroundWorker uses the current SynchronizationContext. You could potentially implement your own subclass of SynchronizationContext to allow you more control (possibly even running code on the same thread, although that will break anything which depends on it running in a different thread) and call SetSynchronizationContext before running the test.
You'd need to subscribe to the event in your test, and then check whether or not your handler was called. (Lambda expressions are good for this.)
For example, suppose you have a SynchronizationContext which lets you run all the work only when you want it to, and tell you when it's done, your test might:
Set the synchronization context
Create the component
Subscribe to the handler with a lambda which sets a local variable
Call LongRunningTask()
Verify that the local variable hasn't been set yet
Make the synchronization context do all its work... wait until it's finished (with a timeout)
Verify that the local variable has now been set
It's all a bit nasty, admittedly. If you can just test the work it's doing, synchronously, that would be a lot easier.
You can create an extension method that can help with turning it into a synchronous call. You can make tweaks like making it more generic and passing in the timeout variable but at least it will make the unit test easier to write.
static class FooExtensions
{
public static SomeData WaitOn(this Foo foo, Action<Foo> action)
{
SomeData result = null;
var wait = new AutoResetEvent(false);
foo.Completed += (s, e) =>
{
result = e.Data; // I assume this is how you get the data?
wait.Set();
};
action(foo);
if (!wait.WaitOne(5000)) // or whatever would be a good timeout
{
throw new TimeoutException();
}
return result;
}
}
public void TestMethod()
{
var foo = new Foo();
SomeData data = foo.WaitOn(f => f.LongRunningTask());
}
For testing asynchronous code I use a similar helper:
public class AsyncTestHelper
{
public delegate bool TestDelegate();
public static bool AssertOrTimeout(TestDelegate predicate, TimeSpan timeout)
{
var start = DateTime.Now;
var now = DateTime.Now;
bool result = false;
while (!result && (now - start) <= timeout)
{
Thread.Sleep(50);
now = DateTime.Now;
result = predicate.Invoke();
}
return result;
}
}
In the test method then call something like this:
Assert.IsTrue(AsyncTestHelper.AssertOrTimeout(() => changeThisVarInCodeRegisteredToCompletedEvent, TimeSpan.FromMilliseconds(500)));