Best use of Windows Service for repeating a progra

2020-06-27 04:21发布

Im building my first Windows Service. It's a component that connects to a mailbox and downloads all mails and store them on my local drive.

My questions are these.

  1. What is the best way to repeat a program call in c# windows service. Im thinking of using a simple timer? Where do I start and stop the timer? is it in the service itself or the program my service is running?

  2. What code should be included in a Windows Service for the following function


protected override void OnStart(string[] args)
{
//timer?
// MyProgram mp = new MyProgram();
}

Should I simply start my application with a new instance like above or should I include more stuff?

As I said this is my first time for using Windows Services so.

EDIT:
Thanks for all the answers. There are of course lots of different ways to do this but I found that best way for me is the one mark as a solution.

Thanks for any help!

3条回答
戒情不戒烟
2楼-- · 2020-06-27 04:43

I use AutoResetEvent with a timeout:

while(!autoResetEvent.WaitOne(MY_MILLISECOND_WAIT))
{
     // do something
}

And when I want to stop, I simply set on the autoResetEvent.

Timer is bad for multiple reason one being Reentry.

OnStart(string[] args) will create the autoResetEvent.


Here is my implementaion of it as PollingWorker:

public class PollingWorker : IDisposable
{

    private const int DEFAULT_INTERVAL_MS = 1000; // 1 second 
    private const int WAIT_INTERVAL = 20; // MS
    private Thread _labourer = null;
    private int _pollingIntervalMS = DEFAULT_INTERVAL_MS;
    private ParameterizedThreadStart _work = null;
    private bool _working = false;
    private object _state = new object();
    private AutoResetEvent _resetTimer = new AutoResetEvent(false);
    private bool _itsTimeToQuite = false;
    private bool _poked = false;
    private bool _isCurrentlyWorking = false;


    public string Name
    {
        get { return _labourer.Name; }
        set { _labourer.Name = value; }
    }

    public PollingWorker(int intervalMS, ParameterizedThreadStart work, object state):
        this(intervalMS, work, state, Guid.NewGuid().ToString())
    {

    }

    public PollingWorker(int intervalMS, ParameterizedThreadStart work, object state, string name)
    {
        _pollingIntervalMS = intervalMS;
        _labourer = new Thread(new ThreadStart(TryDoingSomeWork));
        _labourer.Name = name;
        _work = work;
    }

    public int PollingIntervalMS
    {
        get { return _pollingIntervalMS; }
        set 
        {
            _pollingIntervalMS = value; 
        }
    }

    public void StartWork()
    {
        StartWork(true);
    }

    public void StartWork(bool initialWait)
    {
        _working = true;
        _poked = !initialWait;
        _labourer.Start();
    }


    public void PauseWork()
    {
        _working = false;
    }

    public void Quit()
    {
        Quit(int.MaxValue);
    }

    public void Quit(int maximumWaitToFinishCurrentWorkMS)
    {
        int totalWait = 0;
        _itsTimeToQuite = true;
        _working = false;
        _resetTimer.Set();
        while (_isCurrentlyWorking && Thread.CurrentThread.Name != _labourer.Name) // in case Quit is called from Work 
        {
            Thread.Sleep(WAIT_INTERVAL);
            totalWait += WAIT_INTERVAL;
            if(totalWait>maximumWaitToFinishCurrentWorkMS)
                break;
        }
        Dispose();
    }

    // poke to wake up !
    public void Poke()
    {
        try
        {
            // if you call set on the same thread while it is not on waitOne
            // it does not work 
            if (Thread.CurrentThread.Name == this.Name)
                //_resetTimer.Set();
                _poked = true;
            else
                _resetTimer.Set();
        }
        catch
        { 
            // ignore any error with poking 
        }

    }

    private void TryDoingSomeWork()
    {
        while (!_itsTimeToQuite)
        {
            //Debug.WriteLine(string.Format("{0:ss fff}\t{1}\t{2}\t{3}", DateTime.Now, this.Name, string.Empty, string.Empty));
            if (!_poked) 
                _resetTimer.WaitOne(_pollingIntervalMS, false);

            _poked = false;

            // timed-out which means timer's pulse, so do some work 
            if (_working)
            {
                _isCurrentlyWorking = true;
                _work(_state);
                _isCurrentlyWorking = false;
            }       
        }

    }

    public object State
    {
        get { return _state; }
        set 
        {
            lock (_state)
            {
                _state = value;                 
            }
        }
    }


    public bool Working
    {
        get { return _working; }
    }


    #region IDisposable Members

    public void Dispose()
    {
        try
        {
            _resetTimer.Close();
            _labourer.Abort();
        }
        catch
        { 
            // dont want to raise errors now 
            // so ignore especially threadabortexception!!
        }
    }

    #endregion
}
查看更多
祖国的老花朵
3楼-- · 2020-06-27 04:48

Here's a template you can use it handles the reentrantcy problems with using a timer.

public partial class Service : ServiceBase{

    System.Timers.Timer timer;


 public Service()
    {

    timer = new System.Timers.Timer();
    //When autoreset is True there are reentrancy problme 
    timer.AutoReset = false;


    timer.Elapsed += new System.Timers.ElapsedEventHandler(DoStuff);
}

 protected override void OnStart(string[] args)
 {

     timer.Interval = 1;
     timer.Start();

    }

 private void DoStuff(object sender, System.Timers.ElapsedEventArgs e)
 {

    Collection stuff = GetData();
    LastChecked = DateTime.Now;

    foreach (Object item in stuff)
    {
          item.Dosomthing(); //Do somthing should only be called once
     }     


    TimeSpan ts = DateTime.Now.Subtract(LastChecked);
    TimeSpan MaxWaitTime = TimeSpan.FromMinutes(5);


    if (MaxWaitTime.Subtract(ts).CompareTo(TimeSpan.Zero) > -1)
        timer.Interval = MaxWaitTime.Subtract(ts).Milliseconds;
    else
        timer.Interval = 1;

    timer.Start();





 }

OnContinue OnPause and OnStop are petty easy to work out.

    protected override void OnPause()
    {

        base.OnPause();
        this.timer.Stop();



    }

    protected override void OnContinue()
    {
        base.OnContinue();
        this.timer.Interval = 1;
        this.timer.Start();

    }

    protected override void OnStop()
    {
        base.OnStop();
        this.timer.Stop();
    }
查看更多
聊天终结者
4楼-- · 2020-06-27 04:48

Create a thread or something, no need for a timer! In the OnStart you start the thread and in OnStop you can stop the thread.

查看更多
登录 后发表回答