Undesired termination of Thread created in Timer callback - c#

This is what I want to do:
Have a timer with some interval
In the timer callback code, if some condition is met, another thread should be run
I’ve put my code in a class which is instantiated by the main form and the code is executed upon method call (‘StartSync()’, se sample code).
The problem is that the code runs for a couple of seconds but then terminates. I suppose I’m doing something stupid but I really can’t see what it is. Thankful for any help with regards to this.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
namespace WindowsFormsApplication1
{
class Syncer
{
static bool SYNC_IN_PROGRESS;
public void StartSync()
{
SYNC_IN_PROGRESS = false;
Timer timer = new Timer(timerCallback, null, 0, 1000);
}
public void timerCallback(Object stateInfo)
{
Debug.WriteLine("Sync?");
if (!SYNC_IN_PROGRESS)
{
SYNC_IN_PROGRESS = true;
Thread thSync = new Thread(new ThreadStart(sync));
thSync.Start();
}
}
void sync()
{
Debug.WriteLine("Syncing...");
SYNC_IN_PROGRESS = false;
}
}
}

At a guess, the Timer is only held in a method variable; it sounds to me like the Timer is getting garbage collected and finalized, hence terminated. I suspect you should hold onto that reference in a field to prevent collection.
As an aside - I doubt it is the cause here, but when dealing with threading you should be religiously aware of access to shared state from multiple threads; for example:
using Monitor (aka lock)
appropriate use of volatile
Interlocked when it fits
Your current access to the static bool will probably work OK, but...

Try this cleaner approach
static volatile bool SYNC_IN_PROGRESS;
static thread syncPoll;
public void StartSync()
{
SYNC_IN_PROGRESS = false;
syncPoll = new Thread(sync);
syncPoll.Start();
}
void sync()
{
while (true)
{
Debug.WriteLine("Sync?");
if (SYNC_IN_PROGRESS) Debug.WriteLine("Syncing...");
Thread.Sleep(1000);
}
}
It does the same you try to do with your current code :) but doesn't use a timer

So here is what I did and it seems to work just fine
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
StartSync();
}
static bool SYNC_IN_PROGRESS;
public void StartSync()
{
SYNC_IN_PROGRESS = false;
System.Threading.Timer timer = new System.Threading.Timer(timerCallback, SYNC_IN_PROGRESS, 0, 1000);
}
public void timerCallback(Object stateInfo)
{
Debug.WriteLine("Sync?");
if (!(bool)stateInfo)
{
SYNC_IN_PROGRESS = true;
Thread thSync = new Thread(new ThreadStart(sync));
thSync.Start();
}
}
void sync()
{
Debug.WriteLine("Syncing...");
SYNC_IN_PROGRESS = false;
}
}

Related

C# Start and Stop same thread using 2 different buttons

I have created a simple form home and there is another file Mouse_Tracking.cs.
Mouse_Tracking.cs class is a thread class. I want to start and stop that thread using two different button click in home form.
How can I do this ?
Main form:
namespace computers
{
public partial class home : Form
{
public home()
{
InitializeComponent();
}
private void btn_start_Click(object sender, EventArgs e)
{
var mst = new Mouse_Tracking();
Thread thread1 = new Thread(new ThreadStart(mst.run));
thread1.Start();
}
private void btn_stop_Click(object sender, EventArgs e)
{
//Here I want to stop "thread1"
}
}
}
Computers class:
namespace computers
{
public class Mouse_Tracking
{
public void run()
{
// Some method goes here
}
}
You shouldn't kill threads from the outside. Instead, you should gently ask your thread to terminate, and in your thread you should respond to that request and return from the thread procedure.
You could use an event for that. E.g. add the following to your form class:
AutoResetEvent evtThreadShouldStop = new AutoResetEvent();
In your run method, check if the svtThreadShouldStop event is set every 0.1-1 seconds, if it’s set, return from the thread function, e.g. if( evtThreadShouldStop.WaitOne( 0 ) ) return;
And in your btn_stop_Click call evtThreadShouldStop.Set();
P.S. It’s rarely a good decision to create your own thread: creating and destroying threads is expensive. The runtime already has the thread pool you can use for your own background processing. To post your background task to a pool thread instead use e.g. ThreadPool.QueueUserWorkItem method. You can use same technique with AutoResetEvent to request task termination.
P.P.S. The name of the Mouse_Tracking class suggest you're trying to interact with mouse from the background thread? You can't do that: you can only interact with the GUI including mouse and keyboard from the GUI thread.
Here is an example of what Soonts has suggested. It's quite old-style solution but it's simple and will work fine. But there is a number of other approaches. You can use BackgroundWorker or TPL (Task class), each of which have own thread stop mechanisms.
And I believe that it's ok to create own thread without using existing thread pool if you don't need to do it too often.
public class Mouse_Tracking
{
private ManualResetEvent _stopEvent = new ManualResetEvent(false);
public void stop()
{
_stopEvent.Set();
}
public void run()
{
while (true)
{
if (_stopEvent.WaitOne(0))
{
//Console.WriteLine("stop");
// handle stop
return;
}
//Console.WriteLine("action!");
// some actions
Thread.Sleep(1000);
}
}
}
Sometimes its quite difficult to maintain the thread. You can achieve it by using BackgroundWorker class. You will get complete demonstration on how to use it is here Stop Watch Using Background Worker. I hope it will be useful.
You could use a class like this for controlling your thread(s):
class ThreadController {
private Thread _thread;
public void Start(ThreadStart start) {
if (_thread == null || !_thread.IsAlive) {
_thread = new Thread(start);
_thread.Start();
}
}
public void Stop() {
if (_thread != null && _thread.IsAlive) {
_thread.Interrupt(); // Use _thread.Abort() instead, if your thread does not wait for events.
_thread = null;
}
}
}
Then use:
public partial class home : Form
{
public home()
{
InitializeComponent();
_thread = new ThreadController();
}
private readonly ThreadController _thread;
private void btn_start_Click(object sender, EventArgs e)
{
var mst = new Mouse_Tracking();
_thread.Start(mst.run);
}
private void btn_stop_Click(object sender, EventArgs e)
{
_thread.Stop();
}
}

How can I create a console application that utlilitize async/await

I'm creating a weather app that polls temperature from a service I've made:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace Weather
{
class Program
{
static BackgroundWorker bgw;
static void Main(string[] args)
{
bgw = new BackgroundWorker();
bgw.DoWork += bgw_DoWork;
bgw.RunWorkerAsync();
}
static async void bgw_DoWork(object sender, DoWorkEventArgs e)
{
Weather bot = new Weather();
if (bot.IsRunning)
{
await bot.Update();
}
}
}
public class Weather
{
public bool IsRunning { get; set; }
private DateTime lastUpdated;
public Weather()
{
IsRunning = true;
lastUpdated = DateTime.Now.AddDays(-1);
}
public async Task<bool> Update()
{
if (lastUpdated < DateTime.Now)
{
lastUpdated = DateTime.Now.AddSeconds(30);
// temperature
double value = await GetLatestValue("New York");
}
return true;
}
private async Task<double> GetLatestValue(string city)
{
string url = "http://www" + city;
var client = new WebClient();
string data = await client.DownloadStringTaskAsync(url);
return 4.3;
}
}
}
The problem here is that it does not seem to work? The GetLatesValue function is just jibberish, will just return 4.3 for testing purposes.
What happens is that on await GetLatestValue the console application just quits.
The problem is simpler than you might think: you are running a BackgroundWorker, which basically wraps a thread that has .IsBackground = true. Such threads will not keep a process alive - they will be shut down automatically when the process exits. The process will exit when all non-background threads are completed.
Your Main method starts the BackgroundWorker, but then does nothing else - Main exits, and the application is complete. The BackgroundWorker is then shut down at whatever point it's reached. There's nothing wrong with the code it's running - but the app is shutting down without letting it complete.
EDIT: if you want to test this, simply put a Console.ReadLine() at the end of your Main - it'll keep the application alive until you press Enter, and so you should see your thread run until you do.
In addition to Dan Puzey's answer, there's not much sense in assigning an async void method as an event handler for BackgroundWorker, in the first place.
Your worker method bgw_DoWork will return and the background thread will be finished as soon as the execution point hits the first await inside bgw_DoWork. The bot.Update task most likely still will be pending at that point.
You don't need a BackgroundWorker here. The code can be as simple as this:
static void Main(string[] args)
{
DoWorkAsync().Wait();
}
static async Task DoWorkAsync()
{
Weather bot = new Weather();
if (bot.IsRunning)
{
await bot.Update();
}
}

How to invoke a control within a class

I have a windows form with a button.
I click the button and it starts a method in a separate class. I start this method in a separate thread.
When this class.method finishes it raises an event back to the windows form class.
When this happens I start another method in that separate class that tells a system.windows.form timer (declared in that class) to be enabled and thus start processing.
But the timer does not start (I did put a break point inside the 'tick' event).
I am assuming that it is because I declared the timer outside of the calling thread right at the start of my code.
Normally, I would use this to invoke a method on the same thread...
this.invoke(mydelegatename, any pars);
But, 'this' cannot be called with an class because unassumingly it is related to the UI thread.
I know this all looks bad architecture and I can easily solve this problem by moving the timer to the UI thread (windows form class).
But, I have forgotten how I did this many years ago and it really is an attempt to encapsulate my code.
Can anyone enlighten me pls?
Thanks
The Code:
[windows class]
_webSync = new WebSync(Shared.ClientID);
_webSync.evBeginSync += new WebSync.delBeginSync(_webSync_evBeginSync);
Thread _thSync = new Thread(_webSync.PreConnect);
_thSync.Start();
private void _webSync_evBeginSync()
{
_webSync.Connect();
}
[WebSync class]
private System.Windows.Forms.Timer _tmrManifestHandler = new System.Windows.Forms.Timer();
public WebSyn()
{
_tmrManifestHandler.Tick += new EventHandler(_tmrManifestHandler_Tick);
_tmrManifestHandler.Interval = 100;
_tmrManifestHandler.Enabled = false;
}
public delegate void delBeginSync();
public event delBeginSync evBeginSync;
public void PreConnect()
{
while (true)
{
if (some condition met)
{
evBeginSync();
return ;
}
}
}
public void Connect()
{
_tmrManifestHandler.Enabled = true;
_tmrManifestHandler.Start();
}
private void _tmrManifestHandler_Tick(object sender, EventArgs e)
{
//NOT BEING 'HIT'
}
You have to call _tmrManifestHandler.Start(); enabling is not enough.
Using a System.Windows.Forms.Timer on another thread will not work.
for more info look here.
Use a System.Timers.Timer instead, be carefull of CrossThreadExceptions if you are using accessing UI elements.
public class WebSync
{
private System.Timers.Timer _tmrManifestHandler = new System.Timers.Timer();
public WebSync(object id)
{
_tmrManifestHandler.Elapsed += new System.Timers.ElapsedEventHandler(_tmrManifestHandler_Tick);
_tmrManifestHandler.Interval = 100;
_tmrManifestHandler.Enabled = false;
}
public delegate void delBeginSync();
public event delBeginSync evBeginSync;
public void PreConnect()
{
while (true)
{
if (true /* just for testing*/)
{
evBeginSync();
return;
}
}
}
public void Connect()
{
_tmrManifestHandler.Enabled = true;
_tmrManifestHandler.Start();
}
private void _tmrManifestHandler_Tick(object sender, EventArgs e)
{
//NOT BEING 'HIT'
}
}

Stopping an asynchronous stream outside of the AsyncCallback function

I've got a Stream object and I am using BeginRead to begin reading (obviously) into a buffer; the AsyncCallback function is called once the reading is complete. Within this function I can check if the user wants to get the next 'block' and start the BeginRead process again.
The problem I have is the user may choose to cancel while the stream is still reading (so before the AsyncCallback function is called), so how can I cancel the reading of the stream?
Just to further explain the issue - it seems I would have the same outcome if I use a BackgroundWorker with the Streams Read method or the asynchronous BeginRead method. The user could be left waiting for any length of time for the Read/BeginRead method to complete before I can check if the stream should stop reading.
Edit: The code below should do the job, I'm a million miles away from being anything decent in C# so it may well have a couple of bugs as I doubt it's perfect, although it does demonstrate the solution.
In brief, the CWorkManager manages a certain number of threads (which are held within a CWorkerDetail class). Each CWorkerDetail has a status, which can be EWaiting meaning the worker can be started, EReading which means the worker is reading from a source, during which time the worker can be stopped instantly, EWriting which saves the data that was read to the disk - this cannot be stoppped instantly and this process must complete before the thread is stopped. Finally there is EAborting which is set by the manager if the worker should be aborted as soon as possible; right now this is only set if the worker is in the middle of something which cannot be interrupted (such as writing to disk).
Right now, there isn't actually any reading or writing going on, as that would just complicate the main solution (which is basically just the StopWorker function checking a flag of CWorker to see if it can abort instantly); as such we simply cause the thread to sleep.
The GUI side is fairly simple with just a listbox (which shows the status of each worker) and a stop and start button. All code is below, hope this helps somebody, but as I say I'm not brilliant with C# so please watch out for bugs etc...
CWorkManager.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace ThreadApplication {
//A worker that spawns a number of threads (managed internally) that does nothing useful at all.
public class CWorkManager {
//The status of the worker.
public enum EWorkerStatus {
EWaiting,
EReading,
EWriting,
EAborting,
}
//Holds all data relevant to the worker.
private class CWorkerDetails {
//Simple variables.
private readonly Object _Lock=new Object();
private Thread gThread;
private EWorkerStatus gStatus;
private CWorkManager gParentInstance;
private int gIndex;
//Simple constructor.
public CWorkerDetails(int aIndex, CWorkManager aParentInstance, Thread aThread, EWorkerStatus aStatus) {
gIndex=aIndex;
gParentInstance=aParentInstance;
gThread=aThread;
gStatus=aStatus;
}
//Simple get set methods.
public Thread GetThread() { lock(_Lock) { return gThread; } }
public EWorkerStatus GetStatus() { lock(_Lock) { return gStatus; } }
//Sets the status and automatically updates the GUI.
public void SetStatus(EWorkerStatus aStatus) {
lock(_Lock) {
gStatus=aStatus;
Form1.gInstance.Invoke(new UpdateGUIDelegate(gParentInstance.UpdateGUI), new object[] { gIndex, GetStatus() });
}
}
}
//Worker variable.
private List<CWorkerDetails> gWorkers;
//Simple constructor.
public CWorkManager(int aWorkerCount){
gWorkers=new List<CWorkerDetails>();
for(int tIndex=0; tIndex<aWorkerCount; tIndex++)
gWorkers.Add(null);
}
//Creates and starts the worker.
public void StartWorker(int aWorkerIndex) {
//Create a new worker if there is none or if it is waiting to start.
if(gWorkers.ElementAt(aWorkerIndex)==null||gWorkers.ElementAt(aWorkerIndex).GetStatus()==EWorkerStatus.EWaiting)
gWorkers[aWorkerIndex]=new CWorkerDetails(aWorkerIndex, this, new Thread(new ParameterizedThreadStart(WorkerMethod)), EWorkerStatus.EWaiting);
//If the worker is waiting to start, then start.
if(gWorkers.ElementAt(aWorkerIndex).GetStatus()==EWorkerStatus.EWaiting)
gWorkers.ElementAt(aWorkerIndex).GetThread().Start(gWorkers.ElementAt(aWorkerIndex));
}
//Stops the worker.
public void StopWorker(int aWorkerIndex) {
//Do nothing if the worker is null.
if(gWorkers.ElementAt(aWorkerIndex)==null)
return;
//Do nothing if the worker is waiting.
if(gWorkers.ElementAt(aWorkerIndex).GetStatus()==EWorkerStatus.EWaiting)
return;
//If the worker is reading we can abort instantly.
if(gWorkers[aWorkerIndex].GetStatus()==EWorkerStatus.EReading) {
gWorkers[aWorkerIndex].GetThread().Abort();
gWorkers[aWorkerIndex].SetStatus(EWorkerStatus.EWaiting);
return;
}
//Since the worker is not reading or waiting, we have to request the
//worker to abort by itself.
gWorkers[aWorkerIndex].SetStatus(EWorkerStatus.EAborting);
}
//Updates the GUI.
private delegate void UpdateGUIDelegate(int aIndex, EWorkerStatus aStatus);
private void UpdateGUI(int aIndex, EWorkerStatus aStatus) {
Form1.gInstance.SetThreadStatus(aIndex, aStatus);
}
//This method is where all the real work happens.
private void WorkerMethod(Object aWorker) {
//Fetch worker.
CWorkerDetails mWorker=(CWorkerDetails)aWorker;
//Loop forever, the thread will exit itself when required.
while(true) {
//Is the worker status aborting - if so we stop here.
if(mWorker.GetStatus()==EWorkerStatus.EAborting) {
mWorker.SetStatus(EWorkerStatus.EWaiting);
return;
}
//This would normally be reading from a stream which would cause the thread
//to block, simulate this by just sleeping the thread.
mWorker.SetStatus(EWorkerStatus.EReading);
Thread.Sleep(3000);
//Is the worker status aborting - if so we stop here.
if(mWorker.GetStatus()==EWorkerStatus.EAborting) {
mWorker.SetStatus(EWorkerStatus.EWaiting);
return;
}
//All data has been read, set status to writing and again simulate by
//sleeping the thread.
mWorker.SetStatus(EWorkerStatus.EWriting);
Thread.Sleep(3000);
}
}
}
}
Form1.cs:
Contains:
A List box (ListBox_WorkerStatus)
A button (Button_Start)
A button (Button_Stop)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace ThreadApplication {
public partial class Form1:Form {
public static Form1 gInstance;
private CWorkManager gManager;
public Form1() {
InitializeComponent();
Button_Start.Click+=new EventHandler(Button_Start_Click);
Button_Stop.Click+=new EventHandler(Button_Stop_Click);
gInstance=this;
for(int tIndex=0; tIndex<5; tIndex++)
ListBox_WorkerStatus.Items.Add("Created");
gManager=new CWorkManager(ListBox_WorkerStatus.Items.Count);
}
public void SetThreadStatus(int aIndex, CWorkManager.EWorkerStatus aStatus) {
ListBox_WorkerStatus.Items[aIndex]=aStatus.ToString();
}
private void Button_Start_Click(object sender, EventArgs e) {
if(ListBox_WorkerStatus.SelectedIndex>=0) {
gManager.StartWorker(ListBox_WorkerStatus.SelectedIndex);
}
}
private void Button_Stop_Click(object sender, EventArgs e) {
if(ListBox_WorkerStatus.SelectedIndex>=0) {
gManager.StopWorker(ListBox_WorkerStatus.SelectedIndex);
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e) {
for(int tIndex=0; tIndex<ListBox_WorkerStatus.Items.Count; tIndex++) {
gManager.StopWorker(tIndex);
}
}
}
}
Please Take look atCancel BeginRead this
Use BackgroundWorker
BackgroundWorker backgroundWorker1= new backgroundWorker()
private void InitializeBackgroundWorker()
{
backgroundWorker1.DoWork +=
new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.WorkerSupportsCancellation = true;
}
private void backgroundWorker1_DoWork(object sender,
DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
e.Result = YourWorkToDo();
}
public void Start()
{
backgroundWorker1.RunWorkerAsync()
}
public voic Cancel()
{
backgroundWorker1.CancelAsync();
{
If you want more help leave comment

Windows Forms - How to kick of a seperate thread and hold current thread

I have a windows app and an an dll(windows form) that im trying to open (ActivationCheck), im trying to pause the current thread open a new thread (ActivationCheck) wait for that form event to return true then continue the main thread.
Could someone explain\show me what im doing wrong - thanks.
static class Program
{
private static SplashScreen splash;
private static bool quitApp;
private static bool activationFinished;
[STAThread]
static void Main()
{
Thread thread = new Thread(ActivationCheck);
thread.Start();
do
{
Thread.Sleep(1000);
} while (activationFinished);
if (!quitApp)
{
Thread.Sleep(0);
// WizardRun();
Application.Run(new Main(ref splash));
}
}
}
private static void ActivationCheck()
{
splash.SetStatus = "Checking License...";
Guid productId = new Guid(Properties.Settings.Default.ProductId);
Guid versionId = new Guid(Properties.Settings.Default.VersionId);
Client.UI.EntryPoint entryPoint = new EntryPoint();
activationFinished = false;
Client.BLL.ProductActivation.GenerateTrialLicense(productId1, versionId2, EditionId3);
entryPoint.IniatePlugin(productId, versionId);
entryPoint.PluginFinished += new EventHandlers.PluginFinishEventHandler(entryPoint_PluginFinished);
}
static void entryPoint_PluginFinished(bool forceQuit)
{
quitApp = forceQuit;
activationFinished = true;
}
You could just do thread.Join()? To be honest, though, I'm not quite sure what the point is of starting a second thread and pausing the first; just do the work on the original thread?
The problem with the code is possibly that activationFinished is being held in a register; try marking it as volatile, or alternatively use a lock at both places that access this variable. Even better would be to use a ManualResetEvent or similar, and open it from the activation code.
using System;
using System.Threading;
static class Program
{
static void Main()
{
new Thread(DoActivation).Start();
Console.WriteLine("Main: waiting for activation");
activation.WaitOne();
Console.WriteLine("Main: and off we go...");
}
static void DoActivation(object state)
{
Console.WriteLine("DoActivation: activating...");
Thread.Sleep(2000); // pretend this takes a while
Console.WriteLine("DoActivation: activated");
activation.Set();
// any other stuff on this thread...
}
static ManualResetEvent activation = new ManualResetEvent(false);
}

Categories

Resources