I have a C# Windows Service that runs a few tasks inside.
One of the tasks is a infinite async looping and the others are triggered from a Timer and then execute the task.
private readonly QueueProcessor _queueProcessor;
protected override void OnStart(string[] args)
{
// first task
_queueTask = _queueProcessor.Run(_cancellation.Token);
// second task
affiliate_timer = new System.Timers.Timer();
affiliate_timer.AutoReset = true;
affiliate_timer.Interval = _model.Interval_Affiliate * 60000;
affiliate_timer.Elapsed += new
System.Timers.ElapsedEventHandler(affiliate_timer_Elapsed);
// third task
invoice_timer = new System.Timers.Timer();
invoice_timer.AutoReset = true;
invoice_timer.Interval = _model.Interval_Invoice * 60000;
invoice_timer.Elapsed += new
System.Timers.ElapsedEventHandler(invoice_timer_Elapsed);
}
private void invoice_timer_Elapsed(object source, System.Timers.ElapsedEventArgs e)
{
if (!_isAffiliateBusy)
{
_isAffiliateBusy= true;
var task = Task.Run(() => StartAffiliateTask());
task.Wait();
_isAffiliateBusy= false;
}
}
private void invoice_timer_Elapsed(object source, System.Timers.ElapsedEventArgs e)
{
if (!_isInvoiceBusy)
{
_isInvoiceBusy = true;
var task = Task.Run(() => StartInvoiceTask());
task.Wait();
_isInvoiceBusy = false;
}
}
private void StartAffiliateTask()
{
_affiliateModule = new Modules.Affiliate();
_affiliateModule.RunSync();
}
private void StartInvoiceTask()
{
_invoiceModule = new Modules.Invoice();
_invoiceModule.RunSync();
}
This is my QueueProcessor class that implements await/async to execute a infinite looping job:
public class QueueProcessor
{
private readonly IQueueBroker _serviceBroker;
public QueueProcessor()
{
}
public async Task Run(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
var receiveMessageResponse = await _serviceBroker.ReceiveMessageAsync("test", cancellationToken);
if (!receiveMessageResponse.Messages.Any())
{
continue;
}
foreach (var message in receiveMessageResponse.Messages)
{
// some other tasks here...
await _serviceBroker.DeleteMessageAsync(message, cancellationToken);
}
}
}
}
My Affiliate and Invoice module classes doesn't implement any await/async code inside looks like this:
public class Affiliate
{
/// <summary>
/// Start the sync process
/// </summary>
public void RunSync()
{
try
{
// some code here...
}
catch (Exception ex)
{
}
}
}
My question is:
When my queue procesor infinite loop is running, does my other tasks that are triggered by the timers still can run independently?
When I use:
var task = Task.Run(() => StartAffiliateTask());
task.Wait();
Does the Wait method stop the whole service thread until this task is finished? or that won't block my StartInvoiceTask to run independantly?
Any recommendation on the best way to have my 3 tasks running independant on each other?
Summing up multiple potential issues:
Race condition (access/write to _isBusy).
Potential deadlock (in low ThreadPool size).
Potential incosistent state of flag in case of errors or thread aborts (_isBusy can be left in 'true' state).
Further I will assume your 'task' should be running in single instance, so we will disgard timer callbacks if it is still running.
You should change your timer event handlers like so (best to just wrap it in some kind of class):
//the flag, do mention volatile modifier - it tells particular
//systems to watch for variable changes by reference,
//instead of just copying it into thread stack by value.
private volatile bool _isAffiliateBusy = false;
//sync object for flag to eliminate race condition
private object _affiliateSync = new object();
private void affiliate_timer_Elapsed(object source, System.Timers.ElapsedEventArgs e)
{
//very fast lookup at flag to filter threads which comes when task is still processing
if(_isAffiliateBusy)
return;
lock(_affiliateSync) //taking lock
{
//checking again for those threads which 'happen' to be faster than you think.
if(_isAffiliateBusy)
return;
//aquire lock for business 'task'
_isAffiliateBusy = true;
}
try
{
StartAffiliateTask();
}
finally
{
//resetting singleton business 'task' lock.
//do not forget to use finally block, to handle disposing
//even if something rise up in 'try' section - you will not be left with invalid state of flag.
_isAffiliateBusy = false;
}
}
Related
What is the best solution to quickly cancel long running processes inside background worker?
For example, we have such situation:
private void DoWork(object sender, DoWorkEventArgs e)
{
...
for (int i = 0; i < items; i++)
{
if (_worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
VeryLongRunningProcess();
}
}
}
private void VeryLongRunningProcess()
{
var a = Test();
var b = Test2();
Thread.Sleep(5000);
var c = Test3();
}
In such case, VeryLongRunningProcess() will be not finished on pressing cancel until he finished everything inside his body.
What to do in such cases?
I tried to pass (BackgroundWorker)sender to VeryLongRunningProcess() as param and inside this method check for CancellationPending, but i dont know is this correct way or not
If the problem is isolated your VeryLongRunningProcess from classes like the worker, you can use a Func as a parameter and leave outside your method the worker access
private void VeryLongRunningProcess(Func<bool> isCancelled)
{
var a = Test();
if (isCancelled())
{
return;
}
var b = Test2();
if (isCancelled())
{
return;
}
Thread.Sleep(5000);
var c = Test3();
}
Inside your method, you may check if you must cancel the operation as many times you need. And you can use the Func as a parameter in other methods like Test1, Test2... if any of them takes long time to finish.
Then, you invoke your method in this form:
VeryLongRunningProcess(() => _worker.CancellationPending);
As other people comment, maybe interesting use async/await.
UPDATE
Another way to do if you want choose the use or not of the cancellation:
private void VeryLongRunningProcess(Func<bool> isCancelled = null)
{
var a = Test();
// Or: isCancelled != null && isCancelled()
if (isCancelled?.Invoke() ?? false)
{
return;
}
// ...
}
Normally you should create long-running process as "async" method (public async Task or Task DoWork()) for resources destribution purposes. "CancelationToken" enables cooperative cancellation between threads, thread pool work items. Also it is possible to propagate a callback delegate that can be invoked when Cancellation Token cancelled or function is compleete.
I am building a Winforms Application that does multiple checks on a DB containing sensitive data.
the DB is updating in high frequency 24/7, so the application will check the DB 24/7.
The highest requirement I have is to build the application modular.
That implies that if I need to add additional checks to the application in the future, I can add this with high confidence that i am not messing up the existing checks.
In addition, every check need to be able to Enable/Disable by itself.
I thought to do that by building additional Check Box & Timer combo for each check in the application.
In that way, any additional check is independent (have its own timer and logic) and adding a new check will not change a single line of code in the existing checks.
Code (Test application):
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void check1CheckBox_CheckedChanged(object sender, EventArgs e)
{
check1Timer.Enabled = check1CheckBox.Checked;
}
private void check2CheckBox_CheckedChanged(object sender, EventArgs e)
{
check2Timer.Enabled = check2CheckBox.Checked;
}
private void check3CheckBox_CheckedChanged(object sender, EventArgs e)
{
check3Timer.Enabled = check3CheckBox.Checked;
}
private void check1Timer_Tick(object sender, EventArgs e)
{
check1(); //check DB data
}
private void check2Timer_Tick(object sender, EventArgs e)
{
check2(); //check DB data
}
private void check3Timer_Tick(object sender, EventArgs e)
{
check3(); //check DB data
}
}
I have 2 questions:
1. If in the method explained above, every check is independent and have no way to interrupt/mess with the other checks?
2. What is the "cost" of adding many timers (10+) running in the same time, either in stability/ responsiveness/ timing?
None of the timers will block the form for a long time, every time consuming DB call will be Async (by await calls).
In practice: most of the checks need to run in 2-5 seconds frequency, the maximum frequency will be every second.
Every check have is own frequency and veriables.
Thank you.
The only possible problem I can see, which could be a quite serious problem though, is the problem of overlapping invocations of the event handlers. From the three timers provided by the .NET platform (System.Windows.Forms.Timer, System.Timers.Timer and System.Threading.Timer), none of them prevents overlapping, meaning that the same query could be sent to the database again before the completion of the previous query. The result is that the database could end up being bombarded with more requests than it can handle. Considering that the databases have the tendency to become larger day by day, resulting to queries that become progressively slower, having multiple timers with constant intervals could be a time-bomb for the health of the app, the database, or the system as a whole.
Here are some questions related with the overlapping behavior of the timers, with answers offering solutions to the problem:
Synchronizing a timer to prevent overlap
How to let Timer skip tick if the previous thread is still busy
Timed events overlapping during execution
Here is my own implementation of a non-overlapping Timer, with the behavior I would prefer if I had a similar problem to solve.
/// <summary>
/// Provides a mechanism for executing a method on a thread pool thread,
/// at intervals that are automatically extended to prevent overlapping.
/// </summary>
public class NonOverlappingTimer
{
private readonly object _locker = new object();
private readonly Func<Task> _function;
private CancellationTokenSource _cts = new CancellationTokenSource();
private bool _enabled = false;
private int _interval = 100;
public NonOverlappingTimer(Action action)
{
if (action == null) throw new ArgumentNullException(nameof(action));
_function = () => Task.Run(action);
AsyncLoop();
}
public NonOverlappingTimer(Func<Task> function)
{
if (function == null) throw new ArgumentNullException(nameof(function));
_function = () => Task.Run(function);
AsyncLoop();
}
private async void AsyncLoop()
{
while (true)
{
CancellationToken ct;
bool enabled;
int interval;
lock (_locker)
{
ct = _cts.Token;
enabled = _enabled;
interval = _interval;
}
var delayTask = Task.Delay(enabled ? interval : Timeout.Infinite, ct);
if (enabled) await _function().ConfigureAwait(false);
try
{
await delayTask.ConfigureAwait(false);
}
catch (OperationCanceledException) { } // Suppress this exception
}
}
public bool Enabled
{
get
{
lock (_locker) return _enabled;
}
set
{
CancellationTokenSource cts;
lock (_locker)
{
if (value == _enabled) return;
_enabled = value;
cts = _cts;
_cts = new CancellationTokenSource();
}
cts.Cancel();
}
}
public int Interval
{
get
{
lock (_locker) return _interval;
}
set
{
if (value < 0) throw new ArgumentOutOfRangeException(nameof(value));
CancellationTokenSource cts;
lock (_locker)
{
if (value == _interval) return;
_interval = value;
cts = _cts;
_cts = new CancellationTokenSource();
}
cts.Cancel();
}
}
}
Usage example:
var timer = new NonOverlappingTimer(async () =>
{
Console.WriteLine("Tick");
await Task.Delay(3000); // Simulate a lengthy I/O-bound operation
});
timer.Interval = 2000;
timer.Enabled = true;
Output: a "Tick" will be printed every 3 seconds, although the interval is 2 seconds.
As far as I can see AutoResetEvent and ManualEvent simply control a single signal for cross-thread communication.
Often you would want to know some sort of result in the waiting thread and I can only see the option of storing a class member which is accessed by each thread e.g.:
this.WaitHandle = new AutoResetEvent(false);
DoStuff();
WaitHandle.WaitOne();
lock(this._lock)
{
if(this.Result ...){...}
}
void DoStuff()
{
...
lock(this._lock)
{
this.Result = ...;
}
this.WaitHandle.Set();
}
This is a bit cumbersome so I wondered if there is something built in that will let me pass a value when signalling?
The best approach would be to use the async patterns consistently in all your code.
If you want to actually block execution and wait for the result to be available in a blocking way using traditional methods, you can use a BlockingCollection<T> as a channel to both communicate the result of the operation and that the operation is finished at the same time.
private void button1_Click(object sender, EventArgs e)
{
BlockingCollection<string> blockingQueue = new BlockingCollection<string>();
// Start DoStuff on parallel thread
Task.Run(() => DoStuff(blockingQueue));
// Wait for DoRun to finish AND get the result at the same time
string result = blockingQueue.Take();
MessageBox.Show(result);
}
private void DoStuff(BlockingCollection<string> result)
{
// Simulate work
Thread.Sleep(1000);
// return result
result.Add("SomeResultValue");
}
This also allows you to have two threads adding stuff to the queue and retrieving stuff from the queue at the same time in parallel, the consumer always blocking as long as there is no new data available.
private void button1_Click(object sender, EventArgs e)
{
BlockingCollection<string> blockingQueue = new BlockingCollection<string>();
// Start DoStuff on parallel thread
Task.Run(() => DoStuff(blockingQueue));
// Wait for something to be returned from DoStuff and handle it
foreach (string data in blockingQueue.GetConsumingEnumerable())
{
textBox1.AppendText(data + Environment.NewLine);
}
MessageBox.Show("Finished");
}
private void DoStuff(BlockingCollection<string> result)
{
for (int i = 1; i <= 10; i++)
{
// Simulate work
Thread.Sleep(1000);
// return result
result.Add("Result number " + i);
}
// Signal we are done
result.CompleteAdding();
}
If you use a BlockingCollection with BoundedCapacityset to 1, trying to add to the collection would actually wait until the previous value has been removed.
I found this
Run async method regularly with specified interval
which does half of what I want, but at the same time I want to be able to stop the loop whenever I want and then resume it as well. However while it's stopped, I don't want the infinite loop to keep running where the body gets skipped through a flag.
Basically I don't want this
while (true) {
if (!paused) {
// run work
}
// task delay
}
because then the while loop still runs.
How can I set it so that while its paused, nothing executes?
How can I set it so that while its paused, nothing executes?
That's hard to answer: if you define "pause" as: the object state remains valid while the loop doesn't use any resources then you'll have to stop and restart it (the loop).
All other timers, including Thread.Sleep, Task.Delays etc. will put your thread in idle/suspended mode.
If that's not sufficient for your needs, you'll need to actually stop the "infinite" loop.
It will free up thread related resources as well.
More info about sleep:
Thread.Sleep
More about sleep
You could use System.Threading.Timer and dispose of it while it is not in use and re-create it when you are ready to "resume". These timers are light weight so creating and destroying them on demand is not a problem.
private System.Threading.Timer _timer;
public void StartResumeTimer()
{
if(_timer == null)
_timer = new System.Threading.Timer(async (e) => await DoWorkAsync(e), null, 0, 5000);
}
public void StopPauseTimer()
{
_timer?.Dispose();
_timer = null;
}
public async Task DoWorkAsync(object state)
{
await Task.Delay(500); // do some work here, Task.Delay is just something to make the code compile
}
If you are really adverse to timers and want it to look like a while loop, then you can use TaskCompletionSource<T>:
private TaskCompletionSource<bool> _paused = null;
public async Task DoWork()
{
while (true)
{
if (_paused != null)
{
await _paused.Task;
_paused = null;
}
//run work
await Task.Delay(100);
}
}
public void Pause()
{
_paused = _paused ?? new TaskCompletionSource<bool>();
}
public void UnPause()
{
_paused?.SetResult(true);
}
I'm using the next code to do what I'm asking for :
private delegate void CallerDelegate(object e);
CallerDelegate caler = new CallerDelegate(MethodToCall);
on button click event :
if (currBusyThrd != null && currBusyThrd.IsAlive)
{
currBusyThrd.Abort();
}
ThreadPool.SetMaxThreads(1, 1);
//queue the work for thread processing
ThreadPool.QueueUserWorkItem(new WaitCallback(WaitCallbackMethod))
"WaitCallbackMethod" Method is :
void WaitCallbackMethod(object stateInfo)
{
// argList : i put some argument in a list to use it in "MethodToCall" ...
BeginInvoke(caler,argList);
}
and the method i'm calling by the thread is :
void MethodToCall(object args)
{
//Here I get the thread I'm calling to stop it when btn clicked again
currBusyThrd = Thread.CurrentThread;
// The rest of the code ...
}
I feel that this is wrong ...
How to do it right ?
Actually the calling will be by TextBox_KeyUp .. so every time the user enter a char the code will execute again .. and the BackgroundWorker didn't work .
One problem to this approach is that it's very dangerous to arbitrarily Abort a thread (in pretty much any language). There are too many issues that can popup around unfreed resources and misheld locks. It's typically best to set some kind of flag to ask the Thread to safely abort itself or to forget about the thread and let it run to completion.
Additionally, Aborting a Thread in the ThreadPool is very dangerous and I believe not a supported operation. The Threads in the ThreadPool are not owned by you and Aborting them cold have serious implications for the ThreadPool.
Here is the solution I would take.
private object m_lock = new object();
private bool m_isRunning = false;
private bool m_isAbortRequested = false;
public void OnButtonClick(object sender, EventArgs e) {
lock ( m_lock ) {
if ( m_isRunning ) {
m_isAbortRequested = true;
} else {
m_isAbortRequested = false;
m_isRunning = true;
ThreadPool.QueueUserWorkItem(BackgroundMethod);
}
}
}
private void BackgroundMethod() {
try {
DoRealWork();
} finally {
lock (m_lock) {
m_isRunning = false;
}
}
}
private void DoRealWork() {
...
if ( m_isAbortRequested ) {
return;
}
}
Yes, this is very wrong. You should never try to manually control a ThreadPool thread. If you need this sort of control, you should be using your own Thread object. In addition, Abort() is not the recommended way of ending a thread; you should have a control volatile bool on your form that the code in MethodToCall checks at various points and exits gracefully when it's true. While you can use the same approach with the ThreadPool, the fact that you need to be able to cancel seems to indicate that the process is long-running, or at least has the potential to be. The ThreadPool shouldn't be used for long-running processes.
For example...
private volatile bool stopThread = false;
private Thread workThread;
private void StartThread()
{
if(workThread == null)
{
stopThread = false;
workThread = new Thread(new ThreadStart(MethodToCall));
workThread.Start();
}
}
private void StopThread()
{
if(workThread != null)
{
stopThread = true;
workThread.Join(); // This makes the code here pause until the Thread exits.
workThread = null;
}
}
Then in MethodToCall, just check the stopThread boolean at frequent intervals and do any cleanup work that you need to do and exit the method. For example...
private void MethodToCall()
{
// do some work here and get to a logical stopping point
if(stopThread)
{
// clean up your work
return;
}
// do some more work and get to another stopping point
if(stopThread)
{
// clean up your work
return;
}
}
And just repeat that pattern.
For situations where one thread needs to 'signal' another thread to do something, I usually use a System.Threading.ManualResetEvent to signal the secondary thread to stop, like this:
private volatile bool _threadRunning = false;
private ManualResetEvent _signal = new ManualResetEvent(false);
private Thread _thread;
private void OnButtonClick(object sender, EventArgs e)
{
if (!_threadRunning) {
// Reset the 'signal' event.
_signal.Reset();
// Build your thread parameter here.
object param = ;
// Create the thread.
_thread = new Thread(ExecuteThreadLogicConditionally(param));
// Make sure the thread shuts down automatically when UI closes
_thread.IsBackground = true;
// Start the thread.
_thread.Start();
// Prevent another thread from being started.
_threadRunning = true;
} else {
// Signal the thread to stop.
_signal.Set();
// DO NOT JOIN THE THREAD HERE! If the thread takes a while
// to exit, then your UI will be frozen until it does. Just
// set the signal and move on.
}
}
// If the thread is intended to execute its logic over and over until
// stopped, use this callback.
private void ExecuteThreadLogicUntilStopped(object param)
{
// Use a while loop to prevent the thread from exiting too early.
while (!_signal.WaitOne(0)) {
// Put your thread logic here...
}
// Set the flag so anther thread can be started.
_threadRunning = false;
}
// If the thread logic is to be executed once and then wait to be
// shutdown, use this callback.
private void ExecuteThreadLogicOnce(object param)
{
// Put your thread logic here...
//
// Now wait for signal to stop.
_signal.WaitOne();
// Set the flag so another thread can be started.
_threadRunning = false;
}
// If the thread needs to be stopped at any point along the way, use
// this callback. The key here is to 'sprinkle' checks of the 'signal'
// to see if the thread should stop prematurely.
private void ExecuteThreadLogicConditionally(object param)
{
if (_signal.WaitOne(0)) { _threadRunning = false; return; }
// Execute small chunk of logic here...
if (_signal.WaitOne(0)) { _threadRunning = false; return; }
// Execute another small chuck of logic here...
if (_signal.WaitOne(0)) { _threadRunning = false; return; }
// Continue this pattern through the method.
}
Note that this solution does not use the ThreadPool at all. It could easily be made to do so. And as a suggestion, I wouldn't muck with SetMaxThreads() function on the ThreadPool. Just let the ThreadPool do its thing. It's been designed to be optimal for the way you use it.
Try this code..
using System;
using System.Linq;
using System.Windows.Forms;
using System.Threading;
using System.Diagnostics;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
Thread workerThread = null;
ManualResetEvent threadInterrupt = new ManualResetEvent(false);
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if (this.workerThread == null)
{
this.threadInterrupt.Reset();
this.workerThread = new Thread(() =>
{
int i = 0;
while (!this.threadInterrupt.WaitOne(0))
{
Debug.Print("put your code in here while worker thread running.. " + i.ToString());
Thread.Sleep(100);
i++;
}
this.workerThread = null;
// worker thread finished in here..
});
this.workerThread.IsBackground = true;
// start worker thread in here
this.workerThread.Start();
}
else
{
// stop worker thread in here
threadInterrupt.Set();
}
}
}
}