I want to do some periodic work on a worker thread which signals when the work is completed. When signaled, I want to wait for 5 seconds and re-do the work. I wrote the following code:
public class WinService : ServiceBase
{
private readonly ManualResetEvent stopPeriodicProcess = new ManualResetEvent(false);
protected override void OnStart(string[] args)
{
stopPeriodicProcess.Reset();
ThreadPool.RegisterWaitForSingleObject(stopPeriodicProcess, InitializeEngines, null,5000, true);
}
public void InitializeEngines(object state, bool timedOut)
{
engine.LoadSettings();
Task.Factory.StartNew(engine.DoSomeWork); //Fire and forget
}
private void WorkCompletedEventHandler(object sender, WorkCompletedEventArgs e)
{
ThreadPool.RegisterWaitForSingleObject(stopPeriodicProcess,
(state, timedOut) => DoPeriodicProcess(state, timedOut, e.EngineId), null,
5000, true);
}
public void DoPeriodicProcess(object state, bool timedOut, string engineId)
{
if (timedOut)
{
Task.Factory.StartNew(engine.DoSomeWork); //Fire and forget
}
}
}
public class Engine
{
public event EventHandler<WorkCompletedEventArgs> WorkCompleted;
public void DoSomeWork()
{
//Doing some work..
//Raise an event to signal that the work has been completed
var args = new WorkCompletedEventArgs {EngineId = Settings.EngineId};
RaiseWorkCompletedEvent(args);
}
protected virtual void RaiseWorkCompletedEvent(WorkCompletedEventArgs e)
{
EventHandler<WorkCompletedEventArgs> handler = WorkCompleted;
if (handler != null)
{
handler(this, e);
}
}
}
When I run the code, the CPU usage shows 100% after few seconds. Upon debugging in VS, I see too many alive worker threads waiting at RegisterWaitForSingleObject inside WorkCompletedEventHandler.
Why aren't the threads dying after calling RegisterWaitForSingleObject? Am I missing something?
Not tested but I think this is due to the event not being reset:
private void WorkCompletedEventHandler(object sender, WorkCompletedEventArgs e)
{
stopPeriodicProcess.Reset();
ThreadPool.RegisterWaitForSingleObject(stopPeriodicProcess,
(state, timedOut) => DoPeriodicProcess(state, timedOut, e.EngineId), null,
5000, true);
}
Moreover I don't understand why you're doing things this way, can't you use a timer, which is precisely designed for this kind of use-case?
Related
I want to start / stop a thread in order not to block the UI using button
public partial class Program_Form : Form
{
readonly BackgroundWorker m_oWorker;
[STAThread]
private void Program_Form_Load(object sender, EventArgs e)
{
// long code here
}
private async void DGW6BtnPrint_Click(object sender, EventArgs e)
{
Work.Printer_ Print = new Work.Printer_();
await Task.Run(() =>
{
Print.Print_File(this, dataGridView6, StatusText, progressBar1,
varriablesStatus);
});
}
public void BTN6PPauza_Click(object sender, EventArgs e)
{
//What i had tried
//_canceller.Dispose();
//_canceller.Cancel();
// varriablesStatus = false;
//thread2.break;
//autoResetEvent.WaitOne();
//thread2.Join();
//_manualResetEvent.Reset();
//thread2.Abort();
//_pauseEvent.Reset();
//varriablesStatus = "Pause";
//Print_Actions();
}
}
Referenced class:
namespace OfficeTools.Work
{
class Printer_
{
public void Print_File(Program_Form callForm, DataGridView DGW,
TextBox Status, ProgressBar Progress, bool varriablesStatus)
{
foreach (DataGridViewRow Row in DGW.Rows)
{
file = DGW.Rows[Row.Index].Cells[4].Value.ToString();
PrintFiles.Print_Word(file);
}
}
}
}
How can I start stop pause resume the thread because nothing worked from what I had tried, I think the problem is from the foreach loop
I never used threads, and I can not find an example similar with mine in order to understand how should I do.
What you are asking implies that you want to use the Thread.Suspend and Thread.Resume methods. Possibly like this:
private volatile Thread _printThread;
private async void DGW6BtnPrint_Click(object sender, EventArgs e)
{
Work.Printer_ Print = new Work.Printer_();
await Task.Run(() =>
{
_printThread = Thread.CurrentThread;
try
{
Print.Print_File(this, dataGridView6, StatusText, progressBar1,
varriablesStatus);
}
finally { _printThread = null; }
});
}
public void BTN6PPauza_Click(object sender, EventArgs e)
{
var printThread = _printThread;
if (printThread != null)
{
if (printThread.ThreadState.HasFlag(ThreadState.Running))
{
printThread.Suspend();
}
else if (printThread.ThreadState.HasFlag(ThreadState.Suspended))
{
printThread.Resume();
}
}
}
The documentation of these two methods includes several cautionary warnings that discourage usage:
Thread.Suspend has been deprecated. Use other classes in System.Threading, such as Monitor, Mutex, Event, and Semaphore, to synchronize Threads or protect resources.
Do not use the Suspend and Resume methods to synchronize the activities of threads. You have no way of knowing what code a thread is executing when you suspend it. If you suspend a thread while it holds locks during a security permission evaluation, other threads in the AppDomain might be blocked. If you suspend a thread while it is executing a class constructor, other threads in the AppDomain that attempt to use that class are blocked. Deadlocks can occur very easily.
It's up to you if you want to accept these risks. If you ask me, you shouldn't.
Note: The Suspend and Resume methods are not supported on .NET Core and later platforms. On these platforms they throw a PlatformNotSupportedException exception. You can use them only if you target the .NET Framework platform.
i made this work, i do not know if it is the right way but for the moment it works
public partial class Program_Form : Form
{
readonly BackgroundWorker m_oWorker;
CancellationTokenSource _tokenSource = null;
[STAThread]
private void Program_Form_Load(object sender, EventArgs e)
{
// long code here
}
private async void DGW6BtnPrint_Click(object sender, EventArgs e)
{
_tokenSource = new CancellationTokenSource();
var token = _tokenSource.Token;
Work.Printer_ Print = new Work.Printer_();
await Task.Run(() =>
{
Print.Print_File(this, dataGridView6, StatusText, progressBar1, token);
});
}
public void BTN6PPauza_Click(object sender, EventArgs e)
{
_tokenSource.Cancel();
}
}
Referenced class:
namespace OfficeTools.Work
{
class Printer_
{
public void Print_File(Program_Form callForm, DataGridView DGW, TextBox Status, ProgressBar Progress, CancellationToken Token)
{
foreach (DataGridViewRow Row in DGW.Rows)
{
file = DGW.Rows[Row.Index].Cells[4].Value.ToString();
PrintFiles.Print_Word(file);
if (Token.IsCancellationRequested)
{
try
{
Winword.Quit(ref missing, ref missing, ref missing);
winword = null;
}
catch { }
return;
}
}
}
}
}
Kind regards all
I have a windows service application. I want this windows service to run a method after every x minutes. I also want when the existing method is running, it should not allow the timer method to execute. I have,
private static readonly ILogger Logger = GetLogger();
private Timer _timer;
protected override void OnStart(string[] args)
{
Logger.Log("Starting Timer");
StartTimer();
}
protected override void OnStop()
{
Logger.Log("Stoping Timer");
StopTimer();
}
private void Timer_Elapsed(object state)
{
Logger.Log("Timer Elapsed");
DoWork();
RestartTimer();
}
private static void DoWork()
{
try
{
// Doing my work there
}
catch (Exception ex)
{
Logger.Log(ex);
}
}
private void StartTimer()
{
Logger.Log("Running first time manually");
ThreadPool.QueueUserWorkItem((_) => DoWork());
var frequency = GetTimerFrequency();
_timer = new Timer(Timer_Elapsed, null, frequency, Timeout.Infinite);
}
private void RestartTimer()
{
var frequency = GetTimerFrequency();
_timer.Change(frequency, Timeout.Infinite);
}
private void StopTimer()
{
_timer.Change(Timeout.Infinite, Timeout.Infinite);
_timer.Dispose();
_timer = null;
}
I dunno why but some-times when the method DoWork is running, Timer_Elapsed is executing. I want until one DoWork finished, no more DoWork is allowed to execute.
Possible Duplicate of this post. You have to check the status of the app whether its already running or not.
Here
I made a thread at load event like below:
Thread checkAlert = null;
bool isStop = false;
private void frmMain_Load(object sender, EventArgs e)
{
checkAlert = new Thread(CheckAlert);
checkAlert.Start();
}
void CheckAlert()
{
while (!isStop)
{
Thread.Sleep(60000);
//do work here
}
}
Is there any way to resume the checkAlert thread during it's sleep period?( Thread.Sleep(60000);)
I tried using Thread.Interrupt() but it flows a ThreadInterruptedException, how should I handle this exception? or is there any way to resume the thread?
Edited:
I need to wake up the thread before the "sleep" end because when the user wants to quit the program, the program will have to wait for some time before it really quits ( checkAlert is still running) Is there any way to improve this case?
Based on your comments what it looks like is you need to re-design how CheckAlert works so it does not use Sleep's at all. What you should be doing is using a Timer instead.
System.Timers.Timer timer = null;
public FrmMain()
{
InitializeComponent();
timer = new System.Timers.Timer(60000);
timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
//If you want OnTimedEvent to happen on the UI thread instead of a ThreadPool thread, uncomment the following line.
//timer.SynchronizingObject = this;
if(this.components == null)
this.components = new System.ComponentModel.Container();
//This makes it so when the form is disposed the timer will be disposed with it.
this.componets.Add(timer);
}
private void frmMain_Load(object sender, EventArgs e)
{
timer.Start();
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
//It is good practice not to do complicated logic in a event handler
// if we move the logic to its own method it is much easier to test (you are writing unit tests, right? ;) )
CheckAlert();
}
void CheckAlert()
{
//do work here
}
private void frmMain_Close(object sender, EventArgs e)
{
timer.Stop();
}
If you want the thread to exit automatically when your program quits, simply make it a background thread.
checkAlert = new Thread(CheckAlert);
checkAlert.IsBackground = true;
checkAlert.Start();
It looks to me like you're trying to create a thread which handles two types of events: do something and stop running.
Rather than using a shared variable (isStop) and some other technique to interrupt the thread in order to do work, you might want to use threading events (not to be confused high-level UI Event objects) to control your thread.
AutoResetEvent stop = new AutoResetEvent(false);
AutoResetEvent check = new AutoResetEvent(false);
private void CheckAlert() {
WaitHandle[] handles = new WaitHandle[] { stop, check };
for (;;) {
switch (AutoResetEvent.WaitAny(handles)) {
case 0:
return;
case 1:
// do work
break;
}
}
}
Calling check.Set() in your code will trigger the "do work" branch in the thread and stop.Set() will cause the thread to terminate gracefully.
Once your code has called stop.Set() to terminate the thread, it can call the thread's Join() method to wait until the thread terminates.
EDIT
I misunderstood the question. I will leave the code above in case anyone finds it useful.
If all you want to do is have a thread that performs a task once a minute and stop on demand, you can use the following code:
AutoResetEvent stop = new AutoResetEvent(false);
void CheckAlert() {
var time = new TimeSpan(0, 1, 0); // one minute
while (!stop.WaitOne(time)) {
// do work
}
}
private Thread checkThread;
private void frmMain_Load(object sender, EventArgs e) {
checkThread = new Thread(CheckAlert);
checkThread.Start();
}
private void frmMain_Close(object sender, EventArgs e) {
stop.Set(); // signal thread to stop
checkThread.Join(); // wait for thread to terminate
}
You can see an explanation on how to wake a sleeping thread here:
https://msdn.microsoft.com/en-us/library/tttdef8x%28v=vs.100%29.aspx
and this is a complete example (as you can see, Thread.Interrupt is the good choise... however you have to catch it to continue normal thread execution):
public class HVCSensor : HVCDevice, IDisposable
{
private Thread myThread;
private const int execute_timeout = ((10 + 10 + 6 + 3 + 15 + 15 + 1 + 1 + 15 + 10) * 1000);
private bool disposed = false;
private bool paused = false;
public delegate void HVCResultsHandler(HVC_RESULT res);
public event HVCResultsHandler HVCResultsArrived;
private void OnHVCResultsArrived(HVC_RESULT res)
{
if (HVCResultsArrived != null) {
HVCResultsArrived(res);
}
}
public HVCSensor() {
myThread = new Thread(new ThreadStart(this.execute));
}
private void execute(){
while (!disposed) {
if (!paused && this.IsConnected)
{
HVC_RESULT outRes;
byte status;
try
{
this.ExecuteEx(execute_timeout, activeDetections, imageAcquire, out outRes, out status);
OnHVCResultsArrived(outRes);
}
catch (Exception ex) {
}
}
else {
try
{
Thread.Sleep(1000);
}
catch (ThreadInterruptedException e)
{
}
}
}
}
public HVC_EXECUTION_IMAGE imageAcquire
{
get;
set;
}
public HVC_EXECUTION_FLAG activeDetections
{
get;
set;
}
public void startDetection() {
if(myThread.ThreadState==ThreadState.Unstarted)
myThread.Start();
}
public void pauseDetection() {
paused = true;
}
public void resumeDetection() {
paused = false;
if (myThread.ThreadState == ThreadState.WaitSleepJoin)
myThread.Interrupt();
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
disposed = true;
myThread.Interrupt();
}
}
I'm writing a small application for my Logitech G510 LCD keyboard and am experiencing a little problem. After drawing to my screen, I'd like my program to become idle and remain active as process, but without consuming any resources from my computer.
However, I need to open a Form whenever a certain event is raised. I believe Thread.Sleep() is not the best way to do that.
Here is what my code roughly looks like:
int main(){
InitLCD();
DrawStuff();
Wait();
}
void HandleEvent(){
//Create a Form if none exists
}
//Must be called before exiting
void OnExit()
{
CloseLCD();
}
Could maybe a seperate thread which cares for the event be a solution? If so, how?
EDIT:// The application is an invisible WinForm application. This means, no form is created upon start. Only when said event is raised, an actual form is created.
Try Logic This way :
public static class Program
{
private static AutoResetEvent waithandle = new AutoResetEvent(true);
static void Main()
{
LCDClass lcd = new LCDClass();
lcd.mid_event += LcdOnMidEvent;
lcd.exit_event += LcdOnExitEvent;
lcd.init();
Thread thread = new Thread(lcd.DrawStuff);
thread.Start(waithandle);
waithandle.WaitOne();
}
private static void LcdOnExitEvent(object sendet, EventArgs eventArgs)
{
//lcd work finished
}
private static void LcdOnMidEvent(object sendet, EventArgs eventArgs)
{
// handle event, create form
Application.Run(new MyForm());
}
}
internal class LCDClass
{
private AutoResetEvent waithandle;
internal delegate void MyEventHandler(object sendet, EventArgs e);
internal event MyEventHandler mid_event;
protected virtual void OnMidEvent(object sendet)
{
MyEventHandler handler = mid_event;
if (handler != null) handler(sendet, EventArgs.Empty);
}
internal event MyEventHandler exit_event;
protected virtual void OnExitEvent(object sendet)
{
MyEventHandler handler = exit_event;
if (handler != null) handler(sendet, EventArgs.Empty);
}
public void init()
{
}
public void DrawStuff(object state)
{
// do work here
// raise event
mid_event(this, null);
//do more work
// raise event
exit_event(this, null);
waithandle.Set();
}
}
My question is that is this the best practice to do this. Couldn't find any good examples. I have following code in file created by VS2005:
public partial class ObjectFolder : ServiceBase
{
protected override void OnStart(string[] args)
{
ObjectFolderApp.Initialize();
ObjectFolderApp.StartMonitorAndWork();
}
protected override void OnStop()
{
// TODO: Add code here to perform any tear-down necessary to stop yourservice.
}
}
then:
class ObjectFolderApp
{
public static bool Initialize()
{
//all init stuff
return true;
}
public static void StartMonitorAndWork()
{
Thread worker = new Thread(MonitorAndWork);
worker.Start();
}
private static void MonitorAndWork()
{
int loopTime = 60000;
if (int.TryParse(_cfgValues.GetConfigValue("OfWaitLoop"), out loopTime))
loopTime = 1000 * loopTime;
while (true)
{
/* create+open connection and fill DataSet */
DataSet ofDataSet = new DataSet("ObjectFolderSet");
using (_cnctn = _dbFactory.CreateConnection())
{
_cnctn.Open();
//do all kinds of database stuff
}
Thread.Sleep(loopTime);
}
}
}
Re-hashing my answer from this question, the recommended way is to use a timer and the following code:
public class MyService : ServiceBase
{
private Timer workTimer; // System.Threading.Timer
protected override void OnStart(string[] args)
{
workTimer = new Timer(new TimerCallback(DoWork), null, 5000, 5000);
base.OnStart(args);
}
protected override void OnStop()
{
workTimer.Dispose();
base.OnStop();
}
private void DoWork(object state)
{
RunScheduledTasks(); // Do some work
}
}
Simple!
Note that the Timer type being used is System.Threading.Timer, same as Justin specifies.
Use a System.Threading.Timer to fire the process off at the scheduled interval.