Run loop outside onStart - c#

I'm making a service in C#.
I have the functions:
onStart();
copy();
onStop();
I was running copy() inside the onStart() function. But it was making the service status be set to starting forever, since the copy() function is a loop that runs infinitely (with a Thread.Sleep() inside), making the service unstoppable, unless I finish the proccess in Task Manager.
So, question is:
How can I get copy() to run at the end of onStart() and get onStart() not to wait for the completion of copy()?

You can start new Thread from OnStart so that your service return control back service controller.
protected override void OnStart(string[] args)
{
Thread MyThread = new Thread(new ThreadStart(Starter));
MyThread.Start();
base.OnStart(args);
}
private void Starter()
{
//Add your long running code here
}
You can also use Timer that will be started in OnStart and will keep your service running.
private System.Timers.Timer timer;
protected override void OnStart(string[] args)
{
this.timer = new System.Timers.Timer(3000); // 30000 milliseconds = 30 seconds
this.timer.AutoReset = true;
this.timer.Elapsed += new System.Timers.ElapsedEventHandler(this.timer_Elapsed);
this.timer.Start();
}
protected override void OnStop()
{
this.timer.Stop();
this.timer = null;
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//Your code goes here
}

You can use a new Thread or use a Timer, with the code of an iteration in the Tick event.

Related

Error 1053: Service did not respond in time

I created a new Windows-Service project and added it to the services using sc.exe, but I am always getting the error when I try to execute the Service.
Code in Program:
static void Main() {
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service1()
};
ServiceBase.Run(ServicesToRun);
}
Code in ServiceBase:
public Service1() {
InitializeComponent();
}
protected override void OnStart(string[] args) {
while(true) {
Console.WriteLine("Message all 5 sec...");
Thread.Sleep(5000);
}
}
protected override void OnStop() {
Environment.Exit(0);
}
I tried extending the Timeout in Registry(ServicesPipeTimeout), Using Threads and owning the Service but i still get the error.
Any Help is appreciated.
Kind Regards
Your service will never get out of the onStart-callback because of the endless loop you have created there. So this is blocking and will never finish.
You need to use a timer for your use-case. Just start a timer in your OnStart method and it shall run as expected:
public Service1() {
InitializeComponent();
}
public OnStart(string[] args)
{
Timer timer = new Timer();
timer.Interval = 5000; // 5 seconds
timer.Elapsed += new ElapsedEventHandler(this.OnTimer);
timer.Start();
}
public void OnTimer(object sender, ElapsedEventArgs args)
{
Console.WriteLine("Message all 5 sec...");
}
The timer will send an event every 5 seconds and the added ElapsedEventHandler will call your OnTimer-Method.

GUI updates only after the worker thread has ended

I have a Windows Form application and managed DLL in one solution. DLL contains some time consuming functions during which I wish to update the Form contents (callback from the DLL to the Form with progess updates). I have the following code:
Form code, where I initialize the DLL and give it a callback function in the Initialize method. I also start a separate Thread to periodicly check the message_queue for new messages from the DLL. The DLL function is also called in a separate Thread (non blocking for the UI).
private LibraryDLL library_dll;
private ConcurrentQueue<string> message_queue;
public MainForm()
{
InitializeComponent();
library_dll = new LibraryDLL();
message_queue = new ConcurrentQueue<string>();
library_dll.Initialize(ProcessMessage);
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
string message;
if (message_queue.TryDequeue(out message))
{
PrintMessage(message);
}
}).Start();
}
private void ProcessMessage(string message)
{
message_queue.Enqueue(message);
}
private void PrintMessage(string message)
{
this.Invoke((MethodInvoker)delegate
{
listBox_rows.Items.Add(message);
});
}
private void button_send_Click(object sender, EventArgs e)
{
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
library_dll.DoWork();
}).Start();
}
In DLL code, I use the callback method to report progress:
private CallBack callback;
public delegate void CallBack(string message);
public LibraryDLL() { }
public void Initialize(CallBack callback)
{
this.callback = callback;
}
public void DoWork()
{
callback("working...")
Thread.Sleep(500);
callback("working...")
Thread.Sleep(500);
callback("working...")
Thread.Sleep(500);
}
My problem is, that instead of string "working" appearing every 500ms, it appears 3 times after 1500ms (only after the Thread in which the DoWork method is running ends). I also tried the Invalidate()-Update()-Refresh() sequence in the Form's PrintMessage function, but without any effect.
Thanks for the advice!
EDIT1:
I modified the code to use the BackgroundWorker, however, the problem remains (nothing for 1500ms, than all 3 strings at once).
BackgroundWorker bck_worker;
public MainForm()
{
InitializeComponent();
library_dll = new LibraryDLL();
library_dll.Initialize(bck_worker);
bck_worker = new BackgroundWorker();
bck_worker.ProgressChanged += new ProgressChangedEventHandler(bckWorker_ProgressChanged);
bck_worker.WorkerReportsProgress = true;
bck_worker.WorkerSupportsCancellation = true;
}
private void bckWorker_DoWork(object sender, DoWorkEventArgs e)
{
library_dll.DoWork();
}
private void bckWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
PrintMessage((string)e.UserState);
}
private void button_send_Click(object sender, EventArgs e)
{
bck_worker.DoWork += new DoWorkEventHandler(bckWorker_DoWork);
bck_worker.RunWorkerAsync();
}
private void PrintMessage(string message)
{
listBox_rows.Items.Add(message);
}
And the DLL:
private BackgroundWorker bck_worker;
public LibraryDLL() { }
public void Initialize(BackgroundWorker bck_worker)
{
this.bck_worker = bck_worker;
}
public void DoWork()
{
bck_worker.ReportProgress(25, "working...");
Thread.Sleep(500);
bck_worker.ReportProgress(50, "working...");
Thread.Sleep(500);
bck_worker.ReportProgress(75, "working...");
Thread.Sleep(500);
}
EDIT2:
OK, I now tried to add the Invalidate-Update-Refresh sequence at the end of the PrintMessage function and it finaly works (with the BackgroundWorker approach)!
Use background worker and workers's report progress to update your UI: background worker doc

Changing Timer Interval in Backgroundworker DoWork Disables the Timer [C#]

I have the problem with changing the timer Interval in backgroundworker's DoWork event. While changing the Interval by clicking the Button, Timer stops and doesn't start again.
Does anyone know how to solve this problem?
Simple code:
public Form1()
{
InitializeComponent();
timerTest.Tick += new EventHandler(timerTest_Tick);
timerTest.Interval = 1000;
timerTest.Start();
}
private void buttonTest_Click(object sender, EventArgs e)
{
push = true;
}
private void timerTest_Tick(object sender, EventArgs e)
{
ticks++;
labelTest.Text = ticks.ToString();
if(running == false)
{
running = true;
backgroundWorkerTest.RunWorkerAsync();
}
}
public void activate()
{
timerTest.Stop();
timerTest.Interval = 4000;
timerTest.Start();
}
private void DoWork(object sender, DoWorkEventArgs e)
{
while(running)
{
if(push == true)
{
activate();
}
}
}
private void Completed(object sender, RunWorkerCompletedEventArgs e)
{
running = false;
}
}
}
You never set push to false.
Therefore, the following code:
while(running)
{
if(push == true)
{
activate();
}
}
will continuously call activate() in a tight loop. activate() stops the timer and then restarts it, and the time between calls to it will be far less than the timer interval. Therefore, the timer will never be left long enough to fire.
In any case, why don't you call activate() directly from buttonTest_Click()?
I can see this was asked a long time ago, but for the reference:
When it comes to timers or threadings in general (remember timer is system.threading) in combination with background workers (tasks) Never ever try to change a thread proerties randomly without knowing what the worker is doing.
It is always a good practice when assigning the DoWork handler to prepare the background worker Progress and Complete handlers as well.
At each cycle, report the progress or the completion, this would give you the chance to do your checks and modify another thread properties if needed.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (!worker.CancellationPending)
{
// do task 1 as per the timer1 interval
// do task 2 as per such and such .....
// if I call ChangeInterval here I'll be fiddling with another thread when
// this is still in progress
// that a full loop, Progress will be reported now
}
}
private void backgroundWorker1_ProgressChanged(object sender,ProgressChangedEventArgs e)
{
// Now as the Do work is not in progress
// do something
// check if the user wanted to change the interval ?
// if yes then
ChangeInterval(6000);
// here the progress reporting is done so it will go back to DoWork with the
// NewInterval Value in place and the timer enabled
}
private void ChangeInterval(int NewInterval)
{
timer1.Enabled =false;
timer1.Interval = NewInterval;
timer1.Enabled = true;
}
Try invoke your activate method with the UI Thread's Dispatcher. (Assuming Win Forms?)
this.Invoke(new Action(activate));
Reason is that your timer is a UI control and you're updating the Interval on a separate thread. This will throw a Cross-Thread exception.
Why don't you see the exception? When the DoWork method in your BackgroundWorker throws an exception, it will be propogated to the Completed method. So you should always look at e.Error to see if an exception occurred.
private void Completed(object sender, RunWorkerCompletedEventArgs e)
{
if(e.Error != null)
{
// Oh no something went wrong...
}
running = false;
}
It took me a while, but I found out what was wrong. I'll post you a working code, just in case someone will have the same problem.
public partial class Form1 : Form
{
public int ticks = 0;
public bool running = false;
public bool push = false;
public Form1()
{
InitializeComponent();
timerTest.Tick += new EventHandler(timerTest_Tick);
timerTest.Interval = 1000;
timerTest.Start();
}
private void buttonTest_Click(object sender, EventArgs e)
{
push = true;
}
private void timerTest_Tick(object sender, EventArgs e)
{
ticks++;
labelTest.Text = ticks.ToString();
if(running == false)
{
running = true;
backgroundWorkerTest.RunWorkerAsync();
}
}
public void activate()
{
ZmienIntervalNaAwaryjny = true;
}
public bool ZmienIntervalNaAwaryjny = false;
private void DoWork(object sender, DoWorkEventArgs e)
{
if(push == true)
{
activate();
}
}
private void Completed(object sender, RunWorkerCompletedEventArgs e)
{
if(ZmienIntervalNaAwaryjny == true)
{
timerTest.Stop();
timerTest.Interval = 12000;
timerTest.Start();
}
ZmienIntervalNaAwaryjny = false;
running = false;
}
}

Calling method at the start of windows service in c#

Please look at this piece of code
public partial class TestService : ServiceBase
{
private static System.Timers.Timer aTimer;
protected override void OnStart(string[] args)
{
aTimer = new Timer(10000 * 6 * 5); // 5 minutes interval
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Enabled = true;
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
......
}
}
When I start this service at say 4:00 pm, the first time OnTimedEvent is called is at 4:05 pm, then 4:10 pm and so on. I would like the OnTimedEvent to be called at 4:00 pm as soon as I start the service. Is there anything I am missing here?
Use a System.Threading.Timer rather than a System.Timers.Timer.
It has a constructor overload that in addition to specifying the interval allows you choose the start delay, which can be set to 0 to fire immediately.
For a Comparison of the timer classes, see Windows.Forms.Timer OR System.Threading.Timer (specifically 'Initial timer event schedulable?')
You could just call the event in the OnStart
OnTimedEvent(this, null)
System.Timers.Timer starts counting down from 5 minutes and then the event is triggered. So it won't be able to trigger and run the code till the timer reaches 0.
The code may be run before the event listener is enabled this way shown below:
public partial class TestService : ServiceBase
{
private static System.Timers.Timer aTimer;
protected override void OnStart(string[] args)
{
aTimer = new Timer(10000 * 6 * 5); // 5 minutes interval
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
foo();
aTimer.Enabled = true;
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
foo();
}
private void foo(){
.....
}
}

Converting C# System.Timer to Threading.Timer

i have been using System.Timer to run a windows service but have come across the problem where the timer randomly doesnt fire. I checked it yesterday and it hadnt fired for over 2 hours when its meant to fire every 10 mins. I read this up on Google and apparently its a known problem, the answer being to change over to Threading.Timer. I havent used this before so was looking for some insight. My current code is as follows:
using System;
using System.Timers;
using System.ServiceProcess;
namespace Code
{
public partial class Service : ServiceBase
{
Timer timer = new Timer();
public Service()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
timer.Interval = 10000;
timer.Enabled = true;
}
protected override void OnStop()
{
timer.Enabled = false;
}
private void OnElapsedTime(object source, ElapsedEventArgs e)
{
timer.Enabled = false;
// Run system code here
timer.Interval = 600000;
timer.Enabled = true;
}
}
}
Basically, this normally works fine. The system starts the timer and fires after 10 seconds. It stops the timer, does the job, resets the timer for 10 minutes and enables it. For the most part this always works, but as mentioned randomly decides to stop working, probably due to system resources etc.
If anyone can help me convert this into a Threading.Timer it would be appreciated.
Thanks,
Chris
Here's my best guess - not got time to test it, sorry :(
using System;
using System.Threading;
using System.ServiceProcess;
namespace Code
{
public partial class Service : ServiceBase
{
Timer timer;
AutoResetEvent autoEvent;
bool stopped = true;
public Service()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
stopped = false;
TimerCallback tcb = new TimerCallback(OnElapsedTime);
timer = new Timer(tcb, null, 10000, 600000);
}
protected override void OnStop()
{
stopped = true;
timer.Dispose();
}
private void OnElapsedTime(Object stateInfo)
{
if (stopped)
return;
// Run system code here
}
}
}
http://msdn.microsoft.com/en-us/library/system.threading.timer.aspx
Scroll down to find the example.

Categories

Resources