Stopping a Specific Thread and Starting It Up Again From Windows Service - c#

I want to know how to stop and restart a thread.
I create N amount of threads, depending on conditions returned from a database. These are long running processes which should never stop but should I get a critical error within the thread I want to completely kill the thread and start it up like new.
The code which I use currently to start the threads:
foreach (MobileAccounts MobileAccount in ReceiverAccounts)
{
Receiver rec = new Receiver();
ThreadStart starterParameters = delegate { rec.StartListener(MobileAccount); };
Thread FeedbackThread = new Thread(starterParameters);
FeedbackThread.Name = MobileAccount.FriendlyName;
FeedbackThread.Start();
Thread.Sleep(1000);
}

You can write your own listener and manage its thread within it.
something like:
public class AccountListener
{
private Thread _worker = null;
private MobileAccount _mobileAccount;
public AccountListener(MobileAccount mobileAccount)
{
_mobileAccount = mobileAccount;
}
protected void Listen()
{
try
{
DoWork();
}
catch (Exception exc)
{
}
}
protected virtual void DoWork()
{
Console.WriteLine(_mobileAccount);
}
public void Start()
{
if (_worker == null)
{
_worker = new Thread(Listen);
}
_worker.Start();
}
public void Stop()
{
try
{
_worker.Abort();
}
catch (Exception)
{
//thrad abort exception
}
finally
{
_worker = null;
}
}
}

Related

C# WPF Threading : How to Stop the newly created thread in a event function(Click on a button). without affecting the main thread

Here in the below code I want to stop the thread which is created in StartInvokeExplorer function. Also the starter function in the StartInvokeExplorer is a keyhook function.
public void InvokeExplorerStart_Click(object sender, RoutedEventArgs e)
{
Automate.IsInvokeExplorerClicked = true;
if (InvokeExplorer.Content.Equals("InvokeExplorerStart"))
{
InvokeExplorer.Content = "InvokeExplorerStop";
StartInvokeExplorer();
//InvokeExplorer.Dispatcher.BeginInvoke(new InvokeExplorerDelegate(StartInvokeExplorer));
}
else
{
InvokeExplorer.Content = "InvokeExplorerStart";
StopInvokeExplorer();
}
}
public void StartInvokeExplorer()
{
if (XmlDataGrid.SelectedCells.Count > 0)
{
StartupCount = 1;
thread = new Thread(() =>
{
Starter(StartupCount);
});
thread.IsBackground = true;
thread.Start();
}
else
{
MessageBox.Show("Please select the recorded row to fetch the new data ");
InvokeExplorer.Content = "InvokeExplorerStart";
}
}
private void Starter(int cnt)
{
try
{
if (cnt > 0)
{
Hook.GlobalEvents().MouseClick += (sender, e) =>
{
if (e.Button == MouseButtons.Left)
{
Automate.Show(e);
}
};
Hook.GlobalEvents().MouseDoubleClick += (sender, e) =>
{
Automate.IsDoubleClick = true;
Automate.Show(e);
Automate.IsDoubleClick = false;
};
System.Windows.Forms.Application.Run(new ApplicationContext());
}
else
{
Hook.GlobalEvents().Dispose();
}
}
catch (Exception ex)
{
ErrorLog.Log(ex);
}
}
As from what I have understand, you want to stop the running thread.
This is how.
First, you need to create some stop logic. In your case, it would be some variable, like:
bool threadShouldRun;
and then inside your thread function, you should create a loop like:
void MyThreadFunc()
{
while(threadShouldRun)
{
threadWork();
Thread.Sleep(100);
}
}
When you want to stop the thread, just set your threadShouldRun variable to false.
Sleep is needed here. Without this, thread may use 100% of processor core.
You can use an AutoResetEvent in conjunction with a CancellationToken. Something along the line of (code not tested)
CancellationTokenSource cts;
AutoResetEvent autoResetEvent;
Thread thread;
public void ThreadStart()
{
cts = new CancellationTokenSource();
autoResetEvent = new AutoResetEvent();
thread = new Thread(new ParameterizedThreadStart(ThreadJob));
thread.Start(cts.Token);
}
public void ThreadStop()
{
cts?.Cancel();
thread?.Join();
cts?.Dispose();
autoResetEvent?.Dispose();
}
public static void ThreadJob(object obj)
{
var ct = (CancellationToken)obj;
while (!ct.IsCancellationRequested)
{
if(WaitHandle.WaitAny(new[] { tc.WaitHandle, autoResetEvent}) == 1)
{
// Do your stuff
}
}
}
public void PerformJobInThread()
{
autoResetEvent?.Set();
}
This way your thread will run until you call the ThreadStop method (actually, until you cancel your CancellationTokenSource) but you can still control when to "enable" it.

C# object reference gets SOMETIMES lost in Threads that end via EventHandler

I have a strange problem with following code, that is started about every minute.
Normally everything works fine, but sometimes the HandleCalcStatistikMarkersDone function raises an error because of a NullReferenceException.
I try to explain with the code:
I have a class Strategies. This class is started about every minute to calculate and update some information in a MySQL database. This class is instantiated multiple times in separate threads within a ticker on a form.
public partial class mainForm: Form
{
//do something including ticker, that starts RunStatistik about every minute after the previous thread ended
private void RunStatistik()
{
foreach (InternalObject objPar in InternalObjects)
{
Strategies.StrategyParameter giveParms = new Strategies.StrategyParameter();
giveParms.pair= objPar.pair;
Strategies strat = new Strategies();
Thread calcStatistikThread = new Thread(new ParameterizedThreadStart(strat.CalcCoinStatistik));
calcStatistikThread.Start(giveParms);
}
}
}
Internally in the upper initiated Strategies thread, there are stared some additional threads.
Those threads have a "DoneEvent" which is raised at the end of the function.
To notice, that all threads have ended before the main thread ends, I collect all subthreads in a List CalcStatistikMarkersThreads and wait until the list is empty.
The subthreads should remove themselves out of the upper List via the ThreadDone event.
But sometimes the searched thread (CalcStatistikMarkersThreads.Find) is not found anymore and I get a NullReferenceException.
The question is why?!
Could you tell me, why? And possibly how to prevent?
Thanks in advance.
class Strategies
{ public event EventHandler ThreadDone;
private List<Thread> CalcStatistikMarkersThreads;
//do something
public void CalcCoinStatistik(object parameters)
{
StrategyParameter givenParms = (StrategyParameter)parameters;
Pair internalPair = givenParms.pair
//do something
if (CalcStatistikMarkersThreads == null)
{
CalcStatistikMarkersThreads = new List<Thread>();
}
foreach (InternalTodo in InternalToDos)
{
Strategies strat = new Strategies();
CalcStatistikMarkersParameter csp = new CalcStatistikMarkersParameter();
csp.parm1 = param;
strat.ThreadDone += HandleCalcStatistikMarkersDone;
Thread candleCalc = new Thread(new ParameterizedThreadStart(strat.CalcStatistikMarkers));
CalcStatistikMarkersThreads.Add(candleCalc);
candleCalc.Start(csp);
while (CalcStatistikMarkersThreads.Count != 0)
{
Task.Delay(1000).Wait();
}
}
}
public void CalcStatistikMarkers(object parm)
{
//do something
if (ThreadDone != null)
ThreadDone(this, new ThreadInfoEventArgs(Thread.CurrentThread.ManagedThreadId));
}
public void HandleCalcStatistikMarkersDone(object sender, EventArgs e)
{
Guid workGUID = Guid.NewGuid();
ThreadInfoEventArgs tEv = (ThreadInfoEventArgs)e;
Thread currentThread;
try
{
currentThread = CalcStatistikMarkersThreads.Find(xy => xy.ManagedThreadId == tEv.ThreadID);
//HERE THE NullReferenceException is raised sometimes
CalcStatistikMarkersThreads.Remove(currentThread);
}
catch (Exception ex)
{
throw ex;
}
}
public class ThreadInfoEventArgs : EventArgs
{
private int threadID;
public ThreadInfoEventArgs(int trID)
{
this.threadID = trID;
}
public int ThreadID
{
get { return threadID; }
}
}
}
Cheers
Air

Suggested pattern for gracefully restart cancelled async Tasks on non UI application

I have a console app that instantiates a WeatherClientManager class.
The main thread in the console app requests current weather status in the WeatherClientManager class, but the WeatherClientManager class continuously receives data from a server.
In code:
public static void Main(string [])
{
Program p = new Program();
Task.Run(()=>p.RunLoop());
}
class Program{
WeatherClientManager wcM;
public void RunLoop()
{
wcM = new WeatherClientManager ();
await wcM.InitiateConnection().ConfigureAwait(false);
}
}
class WeatherClientManager
{
public async Task<bool> InitiateConnection()
{
TCPClient tcpClient = new TcpClient(GetTCPDetailsFromConfig())
await tcpClient.ConnectAsync()
CancellationTokenSource cts = new CancellationTokenSource();
if(tcpClient.Connected)
{
Task.Run(()=>ReceiveTask(cts.Token));
Task.Run(()=>SendKeepAlive(cts.Token));
return true;
}
return false;
}
private void ReceiveTask(CancellationToken t)
{
try{
networkStream.Receive(..) // throws exception
}
catch(Exception e)
{
Stop(e);
}
}
private void SendKeepAlive(CancellationToken t)
{
while(!t.IsCancellationRequested)
{
try{
networkStream.Write(..) // throws exception
}
catch(Exception e)
{
Stop(e);
}
}
}
private void Stop(Exception e )
{
log.Error(e);
e.Cancel();
}
}
One of many crap ideas I have is:
Task.Run( () =>
{
while(true)
{
var t1 = Task.Run(()=>ReceiveTask(cts.Token));
var t2= Task.Run(()=>SendKeepAlive(cts.Token));
try{
Tasks.WhenAny(); // should block
}
catch(Exception e)
{
}
finally{
Cleanup();
InitiateConnections();
}
}
}
But I hate the idea of spinning a task to control two sub tasks. My problem is where and how to re-initiate the connection. Any ideas?
EDIT:
I've updated the code such that WeatherClientManager has a OnDisconnectDetected event. So the Program.cs class subscribes like so:
weatherServerManager.OnDisconnectDetected += HandleDisconnectDetection
public async void HandleDisconnectDetection()
{
wsM = new WeatherClientManager ();
wsM.InitiateConnection().ConfigureAwait(false);
}
private void SendKeepAlive(CancellationToken t)
{
while (...)
{
try{}
catch(Exception e)
{
OnDisconnectDetected?.Invoke();
}
}
}
When the handler is invoked by the WeatherClientManager it creates a new task that should continue in a different context. The KeepAlive task should exit then.
Still feels hacky but ideas welcome!
As a general rule, I prefer composition of methods over raising events. In particular, avoid the Task.Run-based fire-and-forget.
In the case of asynchronous sockets, I think it makes sense to give each socket a main loop:
class WeatherClientManager
{
public async Task MainLoop()
{
TCPClient tcpClient = new TcpClient(GetTCPDetailsFromConfig())
await tcpClient.ConnectAsync();
CancellationTokenSource cts = new CancellationTokenSource();
var receiveTask = Task.Run(()=>ReceiveTask(cts.Token));
var keepaliveTask = Task.Run(()=>SendKeepAlive(cts.Token));
await Task.WhenAll(receiveTask, keepaliveTask);
}
}
These can then be composed into the main program's main loop:
class Program
{
public async Task RunLoop()
{
while (true)
{
wcM = new WeatherClientManager();
await wcM.MainLoop();
}
}
}
which in turn is composed into Main:
public static void Main(string [])
{
Program p = new Program();
p.RunLoop().GetAwaiter().GetResult();
}
By avoiding fire-and-forget, you're ensuring that your code will always observe all exceptions. Ignoring tasks is occasionally okay but usually a mistake.

Best way to do a task looping in Windows Service

I have a method that send some SMS to our customers that look like below:
public void ProccessSmsQueue()
{
SmsDbContext context = new SmsDbContext();
ISmsProvider provider = new ZenviaProvider();
SmsManager manager = new SmsManager(context, provider);
try
{
manager.ProcessQueue();
}
catch (Exception ex)
{
EventLog.WriteEntry(ex.Message, EventLogEntryType.Error);
}
finally
{
context.Dispose();
}
}
protected override void OnStart(string[] args)
{
Task.Factory.StartNew(DoWork).ContinueWith( ??? )
}
So, I have some issues:
I donĀ“t know how long it takes for the method run;
The method can throw exceptions, that I want to write on EventLog
I want to run this method in loop, every 10 min, but only after last execution finish.
How I can achieve this? I thought about using ContinueWith(), but I still have questions on how to build the entire logic.
You should have an async method that accepts a CancellationToken so it knows when to stop, calls ProccessSmsQueue in a try-catch block and uses Task.Delay to asynchronously wait until the next time it needs to run:
public async Task DoWorkAsync(CancellationToken token)
{
while (true)
{
try
{
ProccessSmsQueue();
}
catch (Exception e)
{
// Handle exception
}
await Task.Delay(TimeSpan.FromMinutes(10), token);
}
}
You can call this method when your application starts and Task.Wait the returned task before existing so you know it completes and has no exceptions:
private Task _proccessSmsQueueTask;
private CancellationTokenSource _cancellationTokenSource;
protected override void OnStart(string[] args)
{
_cancellationTokenSource = new CancellationTokenSource();
_proccessSmsQueueTask = Task.Run(() => DoWorkAsync(_cancellationTokenSource.Token));
}
protected override void OnStop()
{
_cancellationTokenSource.Cancel();
try
{
_proccessSmsQueueTask.Wait();
}
catch (Exception e)
{
// handle exeption
}
}
Sample Worker Class that I have used in Windows Services. It supports stopping in a 'clean' way by using a lock.
You just have to add your code in DoWork, set your timer in the StartTimerAndWork method (in milliseconds), and use this class in your service.
public class TempWorker
{
private System.Timers.Timer _timer = new System.Timers.Timer();
private Thread _thread = null;
private object _workerStopRequestedLock = new object();
private bool _workerStopRequested = false;
private object _loopInProgressLock = new object();
private bool _loopInProgress = false;
bool LoopInProgress
{
get
{
bool rez = true;
lock (_loopInProgressLock)
rez = _loopInProgress;
return rez;
}
set
{
lock (_loopInProgressLock)
_loopInProgress = value;
}
}
#region constructors
public TempWorker()
{
}
#endregion
#region public methods
public void StartWorker()
{
lock (_workerStopRequestedLock)
{
this._workerStopRequested = false;
}
_thread = new Thread(new ThreadStart(StartTimerAndWork));
_thread.Start();
}
public void StopWorker()
{
if (this._thread == null)
return;
lock (_workerStopRequestedLock)
this._workerStopRequested = true;
int iter = 0;
while (LoopInProgress)
{
Thread.Sleep(100);
iter++;
if (iter == 60)
{
_thread.Abort();
}
}
//if (!_thread.Join(60000))
// _thread.Abort();
}
#endregion
#region private methods
private void StartTimerAndWork()
{
this._timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
this._timer.Interval = 10000;//milliseconds
this._timer.Enabled = true;
this._timer.Start();
}
#endregion
#region event handlers
private void timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (!LoopInProgress)
{
lock (_workerStopRequestedLock)
{
if (this._workerStopRequested)
{
this._timer.Stop();
return;
}
}
DoWork();
}
}
private void DoWork()
{
try
{
this.LoopInProgress = true;
//DO WORK HERE
}
catch (Exception ex)
{
//LOG EXCEPTION HERE
}
finally
{
this.LoopInProgress = false;
}
}
#endregion
}

How to clean the queue from all of the processed items?

There is a global queue of objects that you have to send to your customers. Queue is continually filled with new elements in its flow (one element in a second), that`s why you have to send constantly. Every client is served in a separate thread. After the object is sent to all clients it must be removed from the queue. It seems to be easy, but how to know that all the threads have already sent a particular object?
I do everything on the socket.
Thread threadForClientSending = new Thread(delegate()
{
while (true)
{
try
{
List<SymbolsTable> [] localArrayList ;
//main.que -- global queue
foreach (var eachlist in localArrayList = main.que.ToArray())
{
foreach (var item in eachlist)
{
byte[] message =
encoding.GetBytes((item.GetHashCode()%100).ToString() + " "+item.SDate +"\n\r");
client.Send(message);
}
Thread.Sleep(500);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
break;
}
}
});
Such code sends everything to everyone, but it doesn`t clean the queue.
How to clean the queue from all of the processed items?
public static ConcurrentQueue<List<SymbolsTable>> que = new ConcurrentQueue<List<SymbolsTable>>();
public partial class SymbolsTable
{
public string SName { get; set; }
public Nullable<double> SPrice { get; set; }
public Nullable<int> SVolume { get; set; }
public System.DateTime SDate { get; set; }
}
NOTE: I highly recommend to define local queue for each client (task in server) to achieve maximum concurrency and cleaner code.
You can achieve what you need by using a CountDownEvent which would hold thread access for each item, We should set it to number of available worker that send data to clients.
here is how we can do it:
Definitions:
public static ConcurrentQueue<List<SymbolsTable>> que = new ConcurrentQueue<List<SymbolsTable>>();
public static CountdownEvent counter = new CountdownEvent(NumberOfThreads);
private const int NumberOfThreads = 3; //for example we have 3 clients here
Thread:
Thread threadForClientSending = new Thread(delegate()
{
while (true)
{
try
{
List<SymbolsTable> list;
var peek = que.TryPeek(out list);
if (!peek)
{
Thread.Sleep(100); //nothing to pull
continue;
}
foreach (var item in list)
{
main.que -- global queue
byte[] message =
encoding.GetBytes((item.GetHashCode() % 100).ToString() + " " + item.SDate + "\n\r");
client.Send(message);
Thread.Sleep(500);
}
counter.Signal(); //the thread would signal itself as finished, and wait for others to finish the task
lock (que)
{
List<SymbolsTable> lastList;
if (que.TryPeek(out lastList) && lastList.Equals(list))
{
//just one of the threads would dequeue the item
que.TryDequeue(out lastList);
counter.Reset(); //reset counter for next iteration
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
break;
}
}
});
here we used TryPeek to just access the item in queue so we won't remove it, at the end in:
lock (que)
{
List<SymbolsTable> lastList;
if (que.TryPeek(out lastList) && lastList.Equals(list))
{
//just one of the threads would dequeue the item
que.TryDequeue(out lastList);
counter.Reset(); //reset counter for next iteration
}
}
we would lock the que so only one thread at a time can access it, then we check to see if the processed item has been removed from queue and if not we will remove it here.
More Elegant Solution (in my Humble Opinion):
as you saw in previous solution we're blocking threads to finish the task for each item together,adding a local queue to each thread would remove this blocking mechanism, so we can achieve maximum concurrency.
I suggest something like:
class GlobalQueue
{
private readonly List<IMyTask> _subscribers=new List<IMyTask>();
public void Subscribe(IMyTask task)
{
_subscribers.Add(task);
}
public void Unsubscribe(IMyTask task)
{
_subscribers.Remove(task);
}
public void Enqueue(List<SymbolsTable> table)
{
foreach (var s in _subscribers)
s.Enqueue(table);
}
}
interface IMyTask
{
void Enqueue(List<SymbolsTable> table);
}
which your task would be roughly like:
class MyTask : IMyTask
{
private readonly ConcurrentQueue<List<SymbolsTable>> _localQueue = new ConcurrentQueue<List<SymbolsTable>>();
private readonly Thread _thread;
private bool _started;
public void Enqueue(List<SymbolsTable> table)
{
_localQueue.Enqueue(table);
}
public MyTask()
{
_thread = new Thread(Execute);
}
public void Start()
{
_started = true;
_thread.Start();
}
public void Stop()
{
_started = false;
}
private void Execute()
{
while (_started)
{
try
{
List<SymbolsTable> list;
var peek = _localQueue.TryDequeue(out list);
if (!peek)
{
Thread.Sleep(100); //nothing to pull
continue;
}
foreach (var item in list)
{
byte[] message =
encoding.GetBytes((item.GetHashCode() % 100).ToString() + " " + item.SDate + "\n\r");
client.Send(message);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
break;
}
}
}
}

Categories

Resources