Лучшее использование службы Windows для повторения вызова программы - PullRequest
2 голосов
/ 17 декабря 2010

Я создаю свой первый Windows Service.Это компонент, который подключается к почтовому ящику, загружает все письма и сохраняет их на моем локальном диске.

У меня такие вопросы.

  1. Как лучше всего повторитьвызов программы в c # windows service.Я думаю об использовании простого таймера?Где я могу запустить и остановить таймер?находится ли он в самой службе или в программе, в которой работает моя служба?

  2. Какой код следует включить в службу Windows для выполнения следующей функции


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

Должен ли я просто запустить свое приложение с новым экземпляром, как указано выше, или я должен добавить больше материала?

Как я уже сказал, это мой первый раз, когда я так использую службы Windows.

РЕДАКТИРОВАТЬ:
Спасибо за все ответы.Есть, конечно, много разных способов сделать это, но я обнаружил, что лучший способ для меня - один знак в качестве решения.

Спасибо за любую помощь!

Ответы [ 3 ]

5 голосов
/ 17 декабря 2010

Я использую AutoResetEvent с таймаутом:

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

И когда я хочу остановиться, я просто устанавливаю на autoResetEvent.

Таймер не работает по нескольким причинам, одна из которых Reentry .

OnStart(string[] args) создаст autoResetEvent.


Вот моя реализация этого вида 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
}
4 голосов
/ 17 декабря 2010

Вот шаблон, который вы можете использовать, он решает проблемы повторного входа с использованием таймера.

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 и OnStop очень просты в работе.

    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();
    }
1 голос
/ 17 декабря 2010

Создать поток или что-то, нет необходимости в таймере! В OnStart вы запускаете поток, а в OnStop вы можете остановить поток.

...