I have to wait for an event to be triggered. My initial solution was to use AutoResetEvent and WaitOne(), but the event was always triggered just after the waiting timeout was over. So I went back to the approach below, but I still have the same problem. 2 or 3 seconds after the timeout is over the event gets triggered no matter what the timeout was.
_wait = true;
_delayedResponse = null;
var thread = new Thread(delegate
{
while (_wait)
{
Thread.Sleep(500);
if (_delayedResponse != null)
return;
}
});
thread.Start();
var received = thread.Join(_responseTimeout);
_wait = false;
if (!received)
throw new TimeoutException(
"Timeout for waiting for response reached.");
return _delayedResponse;
Here is the event handler code:
private void OnResponseArrived(object sender, ResponseEventArgs args)
{
_delayedResponse = args.VerificationResponse;
}
The event itself is triggered from another functions that calls the function above.
Basically it looks like this:
var result = DoStuff(); // Library function that is responsible for the event
if (result.Status == Status.Wait)
Wait(); // Function above
Does anyone have an idea what causes this problem and how I can solve it?
EDIT: No longer relevant. Forwarded the OnResponseArrived event, because I found no other solution in time.
Thread.Join is a blocking call - it'll stop the thread you're calling from doing any other work. My guess is that you're waiting for the event on a background thread, but the code that will raise your event is running on the same thread as the code you posted runs in.
By calling thread.Join you're blocking the thread that should be doing your processing. So, you wait for your timeout to expire... then whichever method your posted code is in completes... then your processing actually happens and the ResponseArrived event is raised.
It would be useful if you'd post the rest of your code, but the gist of the solution will be to run the actual work (whatever code raises the ResponseArrived event) in a background thread - and remove the extra threading from the code you posted.
EDIT in response to comment...
In order to synchronise your two pieces of code, you can use an AutoResetEvent. Instead of using Thread.Sleep and your other code, try something like this:
// create an un-signalled AutoResetEvent
AutoResetEvent _waitForResponse = new AutoResetEvent(false);
void YourNewWorkerMethod()
{
_delayedResponse = null;
var result = DoStuff();
// this causes the current thread to wait for the AutoResetEvent to be signalled
// ... the parameter is a timeout value in milliseconds
if (!_waitForResponse.WaitOne(5000))
throw new TimeOutException();
return _delayedResponse;
}
private void OnResponseArrived(object sender, ResponseEventArgs args)
{
_delayedResponse = args.VerificationResponse;
_waitForResponse.Set(); // this signals the waiting thread to continue...
}
Note that you'll need to dispose of the AutoResetEvent when you're done with it.
Well, the first thing you need to do is make sure that DoStuff actually works in a background thread.
If that is correct, the way your code is written right now, you don't event need to spawn a second thread, just to join it one line below, something like this would simply work (as a test):
// handler needs to be attached before starting
library.ResponseReceived += OnResponseReceived;
// call the method
var result = library.DoStuff();
// poll and sleep, but 10 times max (5s)
int watchdog = 10;
while (_delayedResponse == null && watchdog-- > 0)
Thread.Sleep(500);
// detach handler - always clean up after yourself
library.ResponseReceived -= OnResponseReceived;
Console.WriteLine(_delayedResponse != null);
If this works, and you are programming a WinForms app, then you should consider doing the entire thing in a background thread, and then notifying the UI when it's finished. Of course, you will need to provide more details if you need help with that.
Related
i know the common ways of cancelling a backgroundworker using eventwaithandles...
but i wanna know is that right to use a while loop to trap and pause working of a backgroundworker ? i coded like this :
Bool stop = false;
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
progressBar1.Minimum = 0;
progressBar1.Maximum = 100000;
progressBar1.Value = 0;
for (int i = 0; i < 100000; i++)
{
progressBar1.Value++;
if (i == 50000)
stop = true;
while (stop)
{ }
}
}
private void button1_Click(object sender, EventArgs e)
{
stop = !stop;
}
Did you try it? What happened? Was it what you wanted to happen? Did you notice your computer's fans speeding up, to handle all the heat from your CPU in a tight, "do-nothing" loop?
Fact is, you should not "pause" a background task in the first place; if you don't it to keep running, interrupt it. If you want to be able to resume later, provide a mechanism to allow that. Even having your thread blocked efficiently waiting on a WaitHandle object would be the wrong thing to do, because it wastes a thread pool thread.
The code you've posted here is about the worst way to implement "pausing". Instead of waiting on some synchronization object such as a WaitHandle, you have the current thread just loop without interrupting, constantly checking the value of a flag. Even ignoring the question of whether you're using volatile (the code example doesn't show that, but then it also wouldn't compile, so…), it's terrible to force a CPU core to do so much work and yet get nowhere.
Don't pause your BackgroundWorker.DoWork handler in the first place. Really. Just don't do that. But if you insist, then at least use some kind of waitable object instead of a "spin-wait" loop as in the example you've posted here.
Here's an example of how your code might work if you wanted to avoid altogether tying up a thread while "paused". First, don't use BackgroundWorker, because it doesn't have a graceful way to do this. Second, do use await…that does specifically what you want: it allows the current method to return, but without losing track of its progress. The method will resume executing when the thing it waited on indicates completion.
In the example below, I've tried to guess at what the code that calls RunWorkerAsync() looks like. Or rather, I just assumed you've got a button2, which when clicked you call that method to start your worker task. If this is not enough to get you pointed in the right direction, please improve your question by including a good, minimal, complete code example showing what you're actually doing.
// These fields will work together to provide a way for the thread to interrupt
// itself temporarily without actually using a thread at all.
private TaskCompletionSource<object> _pause;
private readonly object _pauseLock = new object();
private void button2_Click(object sender, DoWorkEventArgs e)
{
// Initialize ProgressBar. Note: in your version of the code, this was
// done in the DoWork event handler, but that handler isn't executed in
// the UI thread, and so accessing a UI object like progressBar1 is not
// a good idea. If you got away with it, you were lucky.
progressBar1.Minimum = 0;
progressBar1.Maximum = 100000;
progressBar1.Value = 0;
// This object will perform the duty of the BackgroundWorker's
// ProgressChanged event and ReportProgress() method.
Progress<int> progress = new Progress<int>(i => progressBar1.Value++);
// We do want the code to run in the background. Use Task.Run() to accomplish that
Task.Run(async () =>
{
for (int i = 0; i < 100000; i++)
{
progress.Report(i);
Task task = null;
// Locking ensures that the two threads which may be interacting
// with the _pause object do not interfere with each other.
lock (_pauseLock)
{
if (i == 50000)
{
// We want to pause. But it's possible we lost the race with
// the user, who also just pressed the pause button. So
// only allocate a new TCS if there isn't already one
if (_pause == null)
{
_pause = new TaskCompletionSource<object>();
}
}
// If by the time we get here, there's a TCS to wait on, then
// set our local variable for the Task to wait on. In this way
// we resolve any other race that might occur between the time
// we checked the _pause object and then later tried to wait on it
if (_pause != null)
{
task = _pause.Task;
}
}
if (task != null)
{
// This is the most important part: using "await" tells the method to
// return, but in a way that will allow execution to resume later.
// That is, when the TCS's Task transitions to the completed state,
// this method will resume executing, using any available thread
// in the thread pool.
await task;
// Once we resume execution here, reset the TCS, to allow the pause
// to go back to pausing again.
lock (_pauseLock)
{
_pause.Dispose();
_pause = null;
}
}
}
});
}
private void button1_Click(object sender, EventArgs e)
{
lock (_pauseLock)
{
// A bit more complicated than toggling a flag, granted. But it achieves
// the desirable goal.
if (_pause == null)
{
// Creates the object to wait on. The worker thread will look for
// this and wait if it exists.
_pause = new TaskCompletionSource<object>();
}
else if (!_pause.Task.IsCompleted)
{
// Giving the TCS a result causes its corresponding Task to transition
// to the completed state, releasing any code that might be waiting
// on it.
_pause.SetResult(null);
}
}
}
Note that the above is just as contrived as your original example. If all you had really was a simple single loop variable iterating from 0 to 100,000 and stopping halfway through, nothing nearly so complicated as the above would be required. You'd just store the loop variable in a data structure somewhere, exit the running task thread, and then when you want to resume, pass in the current loop variable value so the method can resume at the right index.
But I'm assuming your real-world example is not so simple. And the above strategy will work for any stateful processing, with the compiler doing all the heavy-lifting of storing away intermediate state for you.
How do I determine when a Eventhandler for a WCF is complete?
I have two static variables that don't get set until the loop I am using to check the status is complete.
Create the variables and call the WCF using the Asynch functions created
static var globalResults;
static bool myEventComplete;
main()
{
globalResults = null;
myEventComplete = false;
WCFClient wcf = new WCFClient();
//create event handler for the WCF asynch call
wcf.MyFuncCompleted += new EventHandler<MyFuncCompletedEventArgs>wcf_MyFuncCompleted);
wcf.MyFuncAsync(wcfParameter.ToString());
int counter = 1;
//Need to determine when the event handler is complete to then use the data returned from the WCF
while (myEventComplete == false && globalResults == null && counter < 10000)
{
counter++;
}
}
//Eventhandler
public static void wcf_MyFuncCompleted(object sender, MyFuncCompletedEventArgs e)
{
globalResults = e.Result;
myEventComplete = true;
}
The eventhandler eventually updates the variables after the loop has completed.
If I duplicate the loop into two sections - the variables get updated in between the two loops - it seems that the event handler isn't running until after the loop (which I don't think is the case) - I just don't know how to get the update values from within the loop.
What's probably happening is that loop is running almost instantly (counting to 10,000 takes practically no time at all). And I'd actually expect the compiler to optimize away the loop unless you use the counter further down.
If the goal is to just do something when the event fires - just call the method you want to run when it completes from within the event itself. There isn't any need for the loop. Are you just attempting to "block" the code until the event fires/completes? I probably wouldn't since it's not needed - just continue the rest of your code that is called by the event itself.
I agree with #Paul Mrozowski.
However, if you have to block the thread, you can block it by defining a static AutoResetEvent object, and in your main call WaitOne() method to block the thread and unblock it with Set()
I do not recommend this if you don't badly need it. You usually can call whatever you want in your wcf_MyFuncCompleted
your main will probably look like this:
// You may reduce its accessibility if needed
public static AutoResetEvent SignalMyThread=new AutoResetEvent(false);
main()
{
WCFClient wcf = new WCFClient();
//create event handler for the WCF asynch call
wcf.MyFuncCompleted += new EventHandler<MyFuncCompletedEventArgs>wcf_MyFuncCompleted);
wcf.MyFuncAsync(wcfParameter.ToString());
// wait for one minute at most, you can specify no time to make it wait indefinitely
SignalMyThread.WaitOne(60000);
}
And just call set in your event handler:
public static void wcf_MyFuncCompleted(object sender, MyFuncCompletedEventArgs e)
{
SignalMyThread.Set();
}
I know there is Thread.Sleep and System.Windows.Forms.Timer and Monitor.Wait in C# and Windows Forms. I just can't seem to be able to figure out how to wait for X seconds and then do something else - without locking the thread.
I have a form with a button. On button click a timer shall start and wait for 5 seconds. After these 5 seconds some other control on the form is colored green. When using Thread.Sleep, the whole application would become unresponsive for 5 seconds - so how do I just "do something after 5 seconds"?
(transcribed from Ben as comment)
just use System.Windows.Forms.Timer. Set the timer for 5 seconds, and handle the Tick event. When the event fires, do the thing.
...and disable the timer (IsEnabled=false) before doing your work in oder to suppress a second.
The Tick event may be executed on another thread that cannot modify your gui, you can catch this:
private System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer();
private void StartAsyncTimedWork()
{
myTimer.Interval = 5000;
myTimer.Tick += new EventHandler(myTimer_Tick);
myTimer.Start();
}
private void myTimer_Tick(object sender, EventArgs e)
{
if (this.InvokeRequired)
{
/* Not on UI thread, reenter there... */
this.BeginInvoke(new EventHandler(myTimer_Tick), sender, e);
}
else
{
lock (myTimer)
{
/* only work when this is no reentry while we are already working */
if (this.myTimer.Enabled)
{
this.myTimer.Stop();
this.doMyDelayedWork();
this.myTimer.Start(); /* optionally restart for periodic work */
}
}
}
}
Just for completeness: with async/await, one can delay execute something very easy (one shot, never repeat the invocation):
private async Task delayedWork()
{
await Task.Delay(5000);
this.doMyDelayedWork();
}
//This could be a button click event handler or the like */
private void StartAsyncTimedWork()
{
Task ignoredAwaitableResult = this.delayedWork();
}
For more, see "async and await" in MSDN.
more completeness:
Depending on your Framework, there is a good chance you will have DispatcherTimer class that can handle the invocation internally (WPF-variants). (finde details in ms docs)
Have you tried
public static Task Delay(
int millisecondsDelay
)
You can use like this:
await Task.Delay(5000);
reference: https://msdn.microsoft.com/en-us/library/hh194873(v=vs.110).aspx
You can start an asynchronous task that performs your action:
Task.Factory.StartNew(()=>
{
Thread.Sleep(5000);
form.Invoke(new Action(()=>DoSomething()));
});
[EDIT]
To pass the interval in you simply have to store it in a variable:
int interval = 5000;
Task.Factory.StartNew(()=>
{
Thread.Sleep(interval);
form.Invoke(new Action(()=>DoSomething()));
});
[/EDIT]
You can wait UI thread the way you want it to work.
Task.Factory.StartNew(async() =>
{
await Task.Delay(2000);
// it only works in WPF
Application.Current.Dispatcher.Invoke(() =>
{
// Do something on the UI thread.
});
});
if you're using .Net Framework 4.5 or higher version, you can use Task.Run instead of Task.Factory.StartNew just like below.
int millisecondsDelay = 2000;
Task.Run(async() =>
{
await Task.Delay(millisecondsDelay);
// it only works in WPF
Application.Current.Dispatcher.Invoke(() =>
{
// Do something on the UI thread.
});
});
You are looking at it wrong.
Click the button, it kicks off a timer with an interval of x seconds. When those are up it's eventhandler executes the task.
So what don't you want to happen.
While the x seconds are elapsing.?
While The task is executing?
If for instance it's you don't want the button to be clicked until delay and task are done. Disable it in the button click handler, and enable it on task completion.
If all you want is a five second delay prior to the task, then you should pass the start delay to the task and let it take care of it.
your application hangs because you are invoking the 5 second sleep/wait on the main UI thread. put the sleep/wait/whatever action in a separate thread (actually System.Windows.Forms.Timer should do that for you) and when it completes invoke the action that turns some control green. remember to check InvokeRequired. here's a short sample (SetText can be called from another thread, if it is the call will instead be invoked on the main UI thread where the textbox is on):
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text = text;
}
}
I took the sample from here (well worth a read!).
#eFloh in the post marked as answer said:
The Tick event may be executed on another thread that cannot modify
your gui, you can catch this ...
That is not what the docs say.
You are using a System.Windows.Forms.Timer in your example code.
That is a Forms.Timer.
According to the C# docs the Timer events are raised on the UI thread.
This Windows timer is designed for a single-threaded environment where
UI threads are used to perform processing. It requires that the user
code have a UI message pump available and always operate from the same
thread ...
Also see stackoverflow post here
Summary:
Within a Windows service & Console Application I am calling a common library that contains a Timer that periodically triggers an action that takes around 30 seconds to complete. This works fine, however...
When a service stop or application exit is called and the timer is in the ElapsedEventHandler I need the service stop/application exit to wait until the event handler has completed.
I have implemented this functionality by having a Boolean InEvent property that is checked when the timer stop method is called.
While this is functional, the question is: Is this the best way to go about doing this? Is there an alternative approach that may serve this purpose better?
The other issue is that I need to avoid the service stop request failing with a "Service failed to respond to stop request"
This is my implementation
public sealed class TimedProcess : IDisposable
{
static TimedProcess singletonInstance;
bool InEvent;
Timer processTimer;
private TimedProcess()
{
}
public static TimedProcess Instance
{
get
{
if (singletonInstance == null)
{
singletonInstance = new TimedProcess();
}
return singletonInstance;
}
}
public void Start(double interval)
{
this.processTimer = new Timer();
this.processTimer.AutoReset = false;
this.processTimer.Interval = interval;
this.processTimer.Elapsed += new ElapsedEventHandler(this.processTimer_Elapsed);
this.processTimer.Enabled = true;
}
public void Stop()
{
if (processTimer != null)
{
while (InEvent)
{
}
processTimer.Stop();
}
}
void processTimer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
InEvent = true;
// Do something here that takes ~30 seconds
}
catch
{
}
finally
{
InEvent = false;
processTimer.Enabled = true;
}
}
public void Dispose()
{
if (processTimer != null)
{
Stop();
processTimer.Dispose();
}
}
}
And this is how it is called in the service OnStart / console application main:
TimedProcess.Instance.Start(1000);
This is how it is called in service OnStop and application main (pending keypress):
TimedProcess.Instance.Stop();
Probably the easiest and most reliable way is to use a Monitor. Create an object that the main program and the timer callback can access:
private object _timerLock = new object();
Your main program tries to lock that before shutting down:
// wait for timer process to stop
Monitor.Enter(_timerLock);
// do shutdown tasks here
And your timer callback locks it, too:
void processTimer_Elapsed(object sender, ElapsedEventArgs e)
{
if (!Monitor.TryEnter(_timerLock))
{
// something has the lock. Probably shutting down.
return;
}
try
{
// Do something here that takes ~30 seconds
}
finally
{
Monitor.Exit(_timerLock);
}
}
The main program should never release the lock once it's obtained it.
If you want the main program to go ahead and shut down after some period of time, regardless of whether it's obtained the lock, use Monitor.TryEnter. For example, this will wait 15 seconds.
bool gotLock = Monitor.TryEnter(_timerLock, TimeSpan.FromSeconds(15));
The return value is true if it was able to obtain the lock.
By the way, I strongly suggest that you use System.Threading.Timer rather than System.Timers.Timer. The latter squashes exceptions, which can end up hiding bugs. If an exception occurs in your Elapsed event, it will never escape, meaning that you never know about it. See my blog post for more information.
EDIT
Each callback to the System.Timers.Timer is queued on the ThreadPool. Be aware that the System.Timers.Timer can have a race condition (you can read more about it here.) System.Threading.Timer is a slightly nicer wrapper which I prefer to use due to it's simplicity.
You haven't described enough details to know if your particular application could handle that race condition, so it's hard to tell. But given your code, it is possible that there might be a callback queued up for processTimer_Elapsed after Stop() is called.
For the service timeout issue --
One way to do this is to make a call to the ServiceController method WaitForStatus with a timeout. I've done this in the past and it works reasonably well, although I recall there being some edge cases around waiting for a very long time.
See the MSDN reference. A sample use is described here.
One possible alternative seems to be to not do the actual work in the timer callback itself but to just queue a work item from there on the tread pool to do the work. Then you can go ahead and dispose of the timer - anything currently running on the thread pool will remain operational, and your service can respond to the stop request immediately but the thread pool item (if queued) will still get processed.
I have this code to pause and resume a thread:
public partial class frmMain : Form
{
(...)
ManualResetEvent wait_handle = new ManualResetEvent(true);
(...)
}
private void frmMain_Shown(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(TheLoop));
}
private void TheLoop(object stateinfo)
{
bool hasInfo = true;
while (doLoop)
{
wait_handle.WaitOne();
bool hasLines = GetInfo();
if (hasLines)
{
//Consuming time Operation 1
System.Threading.Thread.Sleep(7000);
if (CurrentLine < line.Count - 1)
CurrentLine++;
else
{
bool hasInfo2 = GetInfo2();
if (hasInfo2)
{
//Consuming time Operation 2
System.Threading.Thread.Sleep(7000);
}
CurrentLine = 0;
}
}
else
System.Threading.Thread.Sleep(40000); //Wait to query again
}
}
private void btnPauseResume_Click(object sender, EventArgs e)
{
if (btnPauseResume.Text == "Pause")
{
btnPauseResume.Text = "Resume";
wait_handle.Reset();
}
else
{
btnPauseResume.Text = "Pause";
wait_handle.Set();
}
}
The code above shows a cycle information, it works find to pause and resume the "first consuming time operation" but doesn't work for the second one, if I press the button to pause the thread in the second consuming time operation, this one continues and when the first one appears again, then it pauses there.
What am I missing here?
Thx
Have you considered using a Background Worker instead since you are using WinForms? It would probably be easier than trying to 'Pause' a thread. You can check the CancellationPending property to see if a user has elected to cancel the operation. The link has a good sample to look at.
I have never seen someone pausing a thread. Create a delegate and event inside the class or method that you are executing on a separate threat. Execute that event whenever you wish to pause your thred.
There is not any reason that I can see that would prevent a second call to WaitOne from working if placed before the 2nd time consuming operation. Since you are using a ManualResetEvent the wait handle's state will persist until either Set or Reset is called. That means if you resume the thread by calling Set then both calls to WaitOne will pass through. Likewise, if you pause the thread by calling Reset then both calls to WaitOne will block. Of course, it will not be possible to predict where the worker thread will pause if there is more than one call to WaitOne.
Got it guys! the thing is where you put the WaitOne(). For instance, if I have a While Loop (like my example) if I put the wait before it, no matter how many times I hit the pause button, it won't stop the thread, it's logic since the loop already began, but if I put it at the end, then it will work.
Appreciated your help.