Remove delay time: System.Threading.Thread.Sleep using c# (Code Included) - c#

I have a winform app, which shows some information in time, every time it loads the data, I set a delay time of 7 sec like this: System.Threading.Thread.Sleep(7000) so the info can be viewed. I want to have a buttom that allows me to jump to the next information without waiting.
The logic I use is as follows: get Information, if any, wait 7 sec, next data, and so on. So if I press the button I'd like to set that time to 0.
Is there any way to cancel the waiting period?
here is the code:
ManualResetEvent wait_handle = new ManualResetEvent(true);
{...}
private void TheLoop(object stateinfo)
{
bool hasInfo = true;
bool hasLines = GetLinesOnProduction();
while (doLoop)
{
wait_handle.WaitOne();
if (hasLines)
{
param1 = Lines[CurrentLine].line;
param2 = Lines[CurrentLine].WO;
//Here I query the DB for the CurrentLine Data
ShowLineInformation(CurrentLine);
ShowChartByHour(param1, param2, out hasInfo);
if (hasInfo)
System.Threading.Thread.Sleep(7000);
//Here I move to the next line
if (CurrentLine < Lines.Count - 1)
CurrentLine++;
else
{
CurrentLine = 0; //Start all over again
hasLines = GetLinesOnProduction();
}
}
else
{
System.Threading.Thread.Sleep(40000); //(No Lines)Wait to query for lines again
hasLines = GetLinesOnProduction();
}
}
}
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();
}
}

Instead of doing Thread.Sleep, you can use a wait event, and simply set it to cancel the wait. Something like this:
var waiter = new AutoResetEvent(false);
bool wasCanceled = waiter.WaitOne(7000);
if(wasCanceled)
// Jump to next...
// Cancel the wait from another thread
waiter.Set()

Rather than using Thread.Sleep, which will suspend all activity in your UI, use a timer instead. With a timer, the UI can still response to events while your timer callback is pending, and when you click the button, you can cancel the timer.

I would set up the delay by locking an object and then executing a Monitor.Wait on with a delay of 7 seconds. Then, from the form, when the button is pushed, lock the object and do a Monitor.PulseAll.

You could use a ManualResetHandle:
// Declare it as class member
ManualResetHandle _manualResetHandle = new ManualResetHandle();
// Wait in your process for seven seconds, or until it is Set()
_manualResetHandle.WaitOne(7000);
// Set() it in your click event handler:
_manualResetHandle.Set();

Related

c# Task cancellation when using System.Timers

I'm unsure how best to cancel a task that is running a system timer.
In the code below, every 60 mins the timer will elapse and then run another method (CheckFileOverflow) that is used to check the file size of a system log txt. file
Cancellation of the timer ideally would be done by a button click or another method that calls the cancellation. The timer will effectively be allowed to run for as long as the software is running, but when the user eventually shuts down the software i'd like to be able to cancel the task in a responsible fashion i.e. not run the risk of ongoing thread pool resources lingering being used in the background.
I have spent many many hours reading up on cancellation tokens but still don't get it :(
public void SystemEventLoggerTimer()
{
SysEvntLogFileChckTimerRun = true;
Task.Run(() =>
{
System.Timers.Timer timer = new System.Timers.Timer
{ Interval = 1000 * 60 * 60 };
timer.Elapsed += new ElapsedEventHandler(CheckFileOverflow);
timer.Start();
});
}
I'd suggest that you use Microsoft's Reactive Framework (aka Rx) - just NuGet System.Reactive.
Then you do this:
IDisposable subscription =
Observable
.Interval(TimeSpan.FromHours(1.0))
.Subscribe(_ => CheckFileOverflow());
When you want to cancel the subscription just call subscription.Dispose().
Rx is ideal for abstracting away timers, events, tasks, async operations, etc.
You can change your method to something like this
public void SystemEventLoggerTimer(CancellationToken cancelToken)
{
SysEvntLogFileChckTimerRun = true;
Task.Run(async () =>
{
// Keep this task alive until it is cancelled
while (!cancelToken.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromMinutes(60));
CheckFileOverflow();
}
});
}
Then you call SystemEventLoggerTimer like this
var cancelSource = new CancellationTokenSource();
SystemEventLoggerTimer(cancelSource.Token);
you can cancel this Token when program has been disposed or simply at the end of your main function
Why not just have a timer accessible in the calling context (or globally in your class/application) - you'd have to do that with the CancellationTokenSource anyway! This doesn't look like the right use case for a Task.
Try this:
public void SystemEventLoggerTimer(System.Timers.Timer timer)
{
SysEvntLogFileChckTimerRun = true;
timer.Elapsed += new ElapsedEventHandler(CheckFileOverflow);
timer.Start();
}
Calling code:
var timer = new System.Timers.Timer() { Interval = 1000 * 60 * 60 };
SystemEventLoggerTimer(timer);
Cancellation code (in cancel button's event handler, etc):
timer.Stop();
I have posted below what appears to be a satisfactory solution which worked for me. Hopefully I'm responding to the thread in the correct manner... (a newbie to stackOverflow)
I setup a quick windows form for testing, I created 2qty buttons and 1qty textbox.
Buttons are used to Start & Stop the timer (using cancellation token)
The textbox is used to monitor the timer which will update with "Timer Running" message every 2 seconds. Hope this helps anyone else looking at a similar scenario...
enter image description here
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private CancellationTokenSource cancelSource;
// Button is used to START the timer.
private void TimerStartButton_Click(object sender, EventArgs e)
{
cancelSource = new CancellationTokenSource();
// Run the below method that will initiate timer to start running from
// the button click.
SystemEventLoggerTimer(cancelSource.Token);
}
private void SystemEventLoggerTimer(CancellationToken cancelToken)
{
Task.Run(async () =>
{
// Keep this task alive until it is cancelled
while (!cancelToken.IsCancellationRequested)
{
// Encapsulating the function Task.Delay with 'cancelToken'
// allows us to stop the Task.Delay during mid cycle.
// For testing purposes, have reduced the time interval to 2 secs.
await Task.Delay(TimeSpan.FromSeconds(2), cancelToken);
// Run the below method every 2 seconds.
CheckFileOverflow();
}
});
}
// When the below method runs every 2 secs, the UpdateUI will allow
// us to modify the textbox form controls from another thread.
private void CheckFileOverflow()
{
UpdateTextbox("Timer Running");
}
// UpdateUI will allow us to modify the textbox form controls from another thread.
private void UpdateTextbox(string s)
{
Func<int> del = delegate ()
{
textBox1.AppendText(s + Environment.NewLine);
return 0;
};
Invoke(del);
}
// Button that is used to STOP the timer running.
private void TimerStopButton_Click(object sender, EventArgs e)
{
// Initiate the cancelleation request to method "SystemEventLoggerTimer"
cancelSource.Cancel();
}
}

How to terminate/exit/abort old thread workers and restart program?

I have these control buttons (Windows.Forms):
Start/Restart | Pause | Continue
Once Start is pressed, threadPool[workerThreadsCount] is created, ManualResetEvent mre is set to mre.Set() and threads start doing their job. In some pseudo-code:
threadStartingPoint() {
int index = 0;
while(index !== someMaxCondition)
... // grab some data to work on
lock(_lock) { // lock index, so one access at a time
index += index;
}
... // do some stuff
_mre.WaitOne(); // Pause if button Pause is pressed.
}
}
Worker threads work in a loop like in example above. Now if I press pause, everything stop at _mre.Wait(); position. With continue I can open gates using mre.Set() and everything works just fine. Now the problem is when I Pause, I want user to choose between Continue or Restart. The problem with Restart is that I have no idea how to tell my threads to exit that while loop. Because If I just set mre.Set() and create new threads, for some time the old ones will still work with that old data loop.
Any suggestions?
Pass in a CancellationToken and have it checked each loop.
private volatile CancellationTokenSource _tokenSource = new CancellationTokenSource();
threadStartingPoint() {
int index = 0;
var token = _tokenSource.Token;
while(index !== someMaxCondition && !token.IsCancellationRequested)
... // grab some data to work on
lock(_lock) { // lock index, so one access at a time
index += index;
}
... // do some stuff
_mre.WaitOne(); // Pause if button Pause is pressed.
}
}
When the user clicks the Cancel button have it send a Cancel to the CancellationTokenSource the tokens are derived from. Then new workers can just use a new Token Source that are unaffected by the previous cancelation.
private void ButtonCancelClick(object sender, EventArgs e)
{
//Get a local copy of the source and replace the global copy
var tokenSource = _tokenSource;
_tokenSource = new CancellationTokenSource();
//Cancel all loops that used the old token source
tokenSource.Cancel();
mre.Set();
}
The "by the book" answer is to consider implementing a CancellationTokenSource.
But, if you already have working code, I would just add a variable bool restartRequested=false;.
When the user then requests a restart, set restartRequested=true; and reset the _mre. Then break the while loop and let the thread method complete, if restartRequested==true.
You could create another ManualResetEvent that gets set only when the "Restart" button is clicked.
Here's the updated code using the new WaitHandle.
threadStartingPoint() {
int index = 0;
//We have two waithandles that we need to wait on
var waitHandles = new WaitHandle[] {_mre, _restartMre};
while(index !== someMaxCondition)
... // grab some data to work on
lock(_lock) { // lock index, so one access at a time
index += index;
}
... // do some stuff
//Wait on any one of the wait handles to signal
WaitHandle.WaitAny(waitHandles);
if (_restartMre.WaitOne(0)){
break;
}
}
}

Check variable every 5 seconds

I have very complicated mission. I have 2 project that contacts one of each other with TCP connection (listener and client). I want to check in the server program if I got message from the client in the last 5 seconds. The client program send message every 3 seconds automatically if he is connected to the server(The connect function by clicking on "Connect to server" button).
The advanced here is that I need the Server to do other things too so it must to be in thread.
I had an idea that the server contains thread that start when the client send the FIRST message. When the thread start it start the timer every 5 seconds it check a variable that increase every 5 seconds OR every get message(And when I get message I stop the timer and start him from the beginning again).
I tried to do it but without success. I will add my code but it doesn't work. If anyone have an idea I would be very happy I tried for hours to do it.
Code :
//Definition
private int radarPulseNumber;
private int counterTimer; // It the counter of the timer tick's
private bool ifItFirstPulse = true;
private System.Timers.Timer timerForPulse;
private Thread TimerCountRadarPulse;
// Start the thread
TimerCountRadarPulse = new Thread(() => { ifHaveConnection(); });
TimerCountRadarPulse.Start();
private void DrawForPulseMessage(object ls)
{
Dispatcher.Invoke(new Action(() =>
{
if (ifItFirstPulse)
{
ifItFirstPulse = false;
// Create a timer with a 5 second interval.
timerForPulse = new System.Timers.Timer(5000);
// Hook up the Elapsed event for the timer.
timerForPulse.Elapsed += OnTimedEvent;
timerForPulse.Enabled = true;
}
else
{
counterTimer++;
timerForPulse.Stop();
timerForPulse.Start();
}
radarPulseNumber++; // It is the counter how much recieve message we got from the client
lbl_Pulse.Content = "" + radarPulseNumber.ToString();
ImageConnect.Visibility = Visibility.Visible;
ImageDisconnect.Visibility = Visibility.Collapsed;
}));
}
private void OnTimedEvent(Object source, ElapsedEventArgs e)
{
counterTimer++;
}
private void ifHaveConnection() // Actually it's the function that checks the tick's of timer vs the actually recieves.
{
if (l.numOfPulseRecieves != radarPulseNumber) // l.numOfPulseRecives is an field in object who gets the number of recieve from client
{
Dispatcher.Invoke(new Action(() =>
{
// Initiallized variables for reConnect to server.
radarPulseNumber = 0;
counterTimer = 0;
ImageConnect.Visibility = Visibility.Collapsed;
ImageDisconnect.Visibility = Visibility.Visible;
}));
}
}

C# BackgroundWorker

I have a button that on click event I get some information from the network.
When I get information I parse it and add items to ListBox. All is fine, but when I do a fast double-click on button, it seems that two background workers are running and after finishing all work, items in the list are dublicated.
I want to do so that if you click button and the proccess of getting information is in work, this thread is stopping and only after first work is completed the second one is beginning.
Yes, I know about AutoResetEvent, but when I used it it helped me only one time and never more. I can't implement this situation and hope that you will help me!
Now I even try to make easier but no success :( : I added a flag field(RefreshDialogs)(default false), when the user clicks on button, if flag is true(it means that work is doing), nothing is doing, but when flag field is set to false, all is fine and we start a new proccess.
When Backgroundwork completes, I change field flag to false(it means that user can run a new proccess).
private void Message_Refresh_Click(object sender, EventArgs e)
{
if (!RefreshDialogs)
{
RefreshDialogs = true;
if (threadBackgroundDialogs.WorkerSupportsCancellation)
{
threadBackgroundDialogs.CancelAsync();
}
if (!threadBackgroundDialogs.IsBusy)
{
downloadedDialogs = 0;
threadBackgroundDialogs = new BackgroundWorker();
threadBackgroundDialogs.WorkerSupportsCancellation = true;
threadBackgroundDialogs.DoWork += LoadDialogs;
threadBackgroundDialogs.RunWorkerCompleted += ProcessCompleted;
threadBackgroundDialogs.RunWorkerAsync();
}
}
}
void ProcessCompleted(object sender, RunWorkerCompletedEventArgs e)
{
RefreshDialogs = false;
}
So you want to keep the second process running while the first works, but they shouldn't disturb each other? And after the first one finishes the second one continues?
Crude way: While loop:
if (!RefreshDialogs)
{
RefreshDialogs = true;
this becomes:
while(RefreshDialogs)
{
}
RefreshDialogs = true;
After you set it false the second process wwill jump out of the while. (Note this is extremly inefficent since both processes will be running all the time, i'm pretty sure the second one will block the first one, but with multitasking now it shouldn't, if it block use a Dispatcher.Thread)
Elegant way: Use A Semaphore
http://msdn.microsoft.com/de-de/library/system.threading.semaphore%28v=vs.80%29.aspx
If you find it impossible to have both processes running at the same time, or want another way:
Add an Array/List/int and when the second process notices there is the first process running, like with your bool, increase your Added variable, and at the end of the process, restart the new process and decrese the variable:
int number;
if (!RefreshDialogs)
{
RefreshDialogs = true;
your code;
if(number > 0)
{
number--;
restart process
}
}
else
{
number++;
}
I have to admit, i like my last proposal the most, since its highly efficent.
Make your thread blocking. That is easy;
lock(someSharedGlobalObject)
{
Do Work, Exit early if cancelled
}
This way other threads will wait until the first thread releases the lock. They will never execute simultaneously and silently wait until they can continue.
As for other options; why not disable the button when clicked and re-enable it when the backgroundworker completes. Only problem is this does not allow for cancelling the current thread. The user has to wait for it to finish. It does make any concurrency go away very easily.
How about this approach?
Create a request queue or counter which will be incremented on every button click. Every time that count is > 0. Start the background worker. When the information comes, decrement the count and check for 0. If its still > 0 restart the worker. In that your request handler becomes sequential.
In this approach you may face the problem of continuous reference of the count by two threads, for that you may use a lock unlock condition.
I hav followed this approach for my app and it works well, hope it does the same for you.
I'm not an Windows Phone expert, but as I see it has support for TPL, so following code would read nicely:
private object syncRoot =new object();
private Task latestTask;
public void EnqueueAction(System.Action action)
{
lock (syncRoot)
{
if (latestTask == null)
latestTask = Task.Factory.StartNew(action);
else
latestTask = latestTask.ContinueWith(tsk => action());
}
}
Use can use semaphores
class TheClass
{
static SemaphoreSlim _sem = new SemaphoreSlim (3);
static void Main()
{
for (int i = 1; i <= 5; i++)
new Thread (Enter).Start (i);
}
static void Enter (object name)
{
Console.WriteLine (name + " wants to enter");
_sem.Wait();
Console.WriteLine (name + " has entered!");
Thread.Sleep (1000 * (int) name );
Console.WriteLine (name + " is leaving");
_sem.Release(); }
}
}
I found the solution and thanks to #Giedrius. Flag RefreshingDialogs is set to true only when proccess is at the end, when I added items to Listbox. The reason why I'am using this flag is that state of process changes to complete when the asynchronous operation of getting content from network(HttpWebRequest, method BeginGetRequestStream) begins, but after network operaion is complete I need to make UI operations and not only them(parse content and add it to Listbox)My solution is:
private object syncRoot = new object();
private Task latestTask;
public void EnqueueAction(System.Action action)
{
lock (syncRoot)
{
if (latestTask == null)
{
downloadedDialogs = 0;
latestTask = Task.Factory.StartNew(action);
}
else if(latestTask.IsCompleted && !RefreshingDialogs)
{
RefreshingDialogs = true;
downloadedDialogs = 0;
latestTask = Task.Factory.StartNew(action);
}
}
}
private void Message_Refresh_Click(object sender, EventArgs e)
{
Action ac = new Action(LoadDialogs2);
EnqueueAction(ac);
}

How to let Timer skip tick if the previous thread is still busy

I created a windows service, that is supposed to check a certain table in the db for new rows every 60 seconds. For every new row that was added, I need to do some heavy processing on the server that could sometimes take more than 60 seconds.
I created a Timer object in my service, that ticks every 60 seconds and invokes the wanted method.
Since I don't want this timer to tick while processing the new lines found, I wrapped the method in a lock { } block, so this won't be accessible by another thread.
It looks something like this :
Timer serviceTimer = new Timer();
serviceTimer.Interval = 60;
serviceTimer.Elapsed += new ElapsedEventHandler(serviceTimer_Elapsed);
serviceTimer.Start();
void serviceTimer_Elapsed(object sender, ElapsedEventArgs e)
{
lock (this)
{
// do some heavy processing...
}
}
Now, I'm wondering -
If my timer ticks, and finds a lot of new rows on the db, and now the processing will take more than 60 seconds, the next tick won't do any processing till the previous one finished. This is the effect I want.
But now, will the serviceTimer_Elapsed method go off immediatly once the first processing was finished, or will it wait for the timer to tick again.
What I want to happen is - if the processing requires more than 60 seconds, than the timer will notice the thread is locked, and wait another 60 seconds to check again so I will never get stuck in a situation where there are a queue of threads waiting for the previous one to finish.
How can i accomplish this result ?
What is the best practice for doing this ?
Thanks!
You might try disabling the timer during processing, something like
// Just in case someone wants to inherit your class and lock it as well ...
private static object _padlock = new object();
try
{
serviceTimer.Stop();
lock (_padlock)
{
// do some heavy processing...
}
}
finally
{
serviceTimer.Start();
}
Edit : OP didn't specify whether the reentrancy was caused only by the timer or whether the service was multi threaded. Have assumed the later, but if the former then locking should be unnecessary if the timer is stopped (AutoReset or manually)
You don't need the lock in this case. Set timer.AutoReset=false before starting it.
Restart the timer in the handler after you are done with your processing. This will ensure that the timer fires 60 seconds after each task.
A similar variation on other answers, that allows the timer to keep ticking and only do the work when the lock can be obtained, instead of stopping the timer.
Put this in the elapsed event handler:
if (Monitor.TryEnter(locker)
{
try
{
// Do your work here.
}
finally
{
Monitor.Exit(locker);
}
}
Put a quick check it see if the service is running. if it is running it will skip this event and wait for the next one to fire.
Timer serviceTimer = new Timer();
serviceTimer.Interval = 60;
serviceTimer.Elapsed += new ElapsedEventHandler(serviceTimer_Elapsed);
serviceTimer.Start();
bool isRunning = false;
void serviceTimer_Elapsed(object sender, ElapsedEventArgs e)
{
lock (this)
{
if(isRunning)
return;
isRunning = true;
}
try
{
// do some heavy processing...
}
finally
{
isRunning = false;
}
}
I recommend you don't let the timer tick at all while its processing.
Set the Timers AutoReset to false. And start it at the end. Here's a full answer you might be interested in
Needed: A Windows Service That Executes Jobs from a Job Queue in a DB; Wanted: Example Code
Other options might be to use a BackGroundWorker class, or TheadPool.QueueUserWorkItem.
Background worker would easily give you the option check for current processing still occurring and process 1 item at a time. The ThreadPool will give you the ability to continue queueing items every tick (if necessary) to background threads.
From your description, I assume you are checking for items in a queue in a database. In this case, I would use the ThreadPool to push the work to the background, and not slow/stop your checking mechanism.
For a Service, I would really suggest you look at using the ThreadPool approach. This way, you can check for new items every 60 seconds with your timer, then Queue them up, and let .Net figure out how much to allocate to each item, and just keep pushing the items into the queue.
For Example: If you just use a timer and you have 5 new rows, which require 65 seconds of processing time total. Using the ThreadPool approach, this would be done in 65 seconds, with 5 background work items. Using the Timer approach, this will take 4+ minutes (the minute you will wait between each row), plus this may cause a back-log of other work that is queueing up.
Here is an example of how this should be done:
Timer serviceTimer = new Timer();
void startTimer()
{
serviceTimer.Interval = 60;
serviceTimer.Elapsed += new ElapsedEventHandler(serviceTimer_Elapsed);
serviceTimer.AutoReset = false;
serviceTimer.Start();
}
void serviceTimer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
// Get your rows of queued work requests
// Now Push Each Row to Background Thread Processing
foreach (Row aRow in RowsOfRequests)
{
ThreadPool.QueueUserWorkItem(
new WaitCallback(longWorkingCode),
aRow);
}
}
finally
{
// Wait Another 60 Seconds and check again
serviceTimer.Stop();
}
}
void longWorkingCode(object workObject)
{
Row workRow = workObject as Row;
if (workRow == null)
return;
// Do your Long work here on workRow
}
There's quite a neat way of solving this with Reactive Extensions. Here's the code, and you can read a fuller explanation here: http://www.zerobugbuild.com/?p=259
public static IDisposable ScheduleRecurringAction(
this IScheduler scheduler,
TimeSpan interval,
Action action)
{
return scheduler.Schedule(
interval, scheduleNext =>
{
action();
scheduleNext(interval);
});
}
And you could use it like this:
TimeSpan interval = TimeSpan.FromSeconds(5);
Action work = () => Console.WriteLine("Doing some work...");
var schedule = Scheduler.Default.ScheduleRecurringAction(interval, work);
Console.WriteLine("Press return to stop.");
Console.ReadLine();
schedule.Dispose();
another posibility would be something like this:
void serviceTimer_Elapsed(object sender, ElapsedEventArgs e)
{
if (System.Threading.Monitor.IsLocked(yourLockingObject))
return;
else
lock (yourLockingObject)
// your logic
;
}

Categories