防止多个服务实例 - 最好的方法?

Fra*_*rme 20 c# windows service multithreading

那么您认为防止C#Windows服务的多个线程同时运行的最佳方法是什么(该服务是否使用了timerOnElapsed事件)?

使用lock()mutex

我似乎无法掌握这个概念mutex,但使用lock()似乎对我的情况很好.

我是否应该花时间学习如何使用mutex

Jim*_*hel 61

使您的计时器一次性,并在已用事件处理程序中重新初始化它.例如,如果您正在使用System.Timers.Timer,则将其初始化为:

myTimer.Elapsed = timer1Elapsed;
myTimer.Interval = 1000; // every second
myTimer.AutoReset = false; // makes it fire only once
myTimer.Enabled = true;
Run Code Online (Sandbox Code Playgroud)

你过去的事件处理程序:

void timerElapsed(object source, ElapsedEventArgs e)
{
    // do whatever needs to be done
    myTimer.Start(); // re-enables the timer
}
Run Code Online (Sandbox Code Playgroud)

这样做的缺点是计时器不会在一秒间隔内发射.相反,它会在最后一个滴答处理完成后触发一秒钟.

  • @ flagg19:如果使用`System.Threading.Timer`,则使用等于`Timeout.Infinite`的最后一个参数进行初始化.在回调中,你将调用`Change`,最后一个参数等于`Timeout.Infinite. (2认同)
  • 您可以在计时器开始时使用秒表,然后测量经过的时间。然后根据经过的时间进行延迟以获得相当均匀的计时器。如果您的工作花费的时间比计时器之间所需的时间长度长,那么您的延迟将为 0。如果需要半秒,那么您将延迟半秒,依此类推。 (2认同)

Mar*_*mes 10

不要使用计时器来生成线程.只开始一个线程.当线程完成一个工作循环时,计算下一个循环开始之前剩余的时间.如果此间隔为0或负数,则立即循环并开始新的循环,如果为正,则在循环返回之前休眠该间隔.

这通常通过在完成刻度和开始刻度之间取无符号int减法的int结果来完成,因此给出工作所经过的刻度.从期望的间隔中减去该值可以得到新的剩余时间.

不需要额外的计时器线程,不可能同时运行两个线程,简化整体设计,不连续创建/启动/终止/销毁,没有mallocs,没有new(),没有堆栈分配/解除分配,没有GC.

使用定时器,互斥锁,信号量,锁等的其他设计过于复杂.如果只是更容易和更简单地不进行任何额外的线程,为什么还要尝试使用同步停止额外的线程呢?

有时,使用计时器而不是sleep()循环只是一个非常糟糕的主意.这听起来像是其中一个时代.

public void doWorkEvery(int interval)
{
    while (true)
    {
        uint startTicks;
        int workTicks, remainingTicks;
        startTicks = (uint)Environment.TickCount;
        DoSomeWork();
        workTicks=(int)((uint)Environment.TickCount-startTicks);
        remainingTicks = interval - workTicks;
        if (remainingTicks>0) Thread.Sleep(remainingTicks);
    }
}
Run Code Online (Sandbox Code Playgroud)


mis*_*ika 5

如果另一个计时器线程已经在执行回调,则可以使用Monitor.TryEnter()来代替锁定

class Program
{
    static void Main(string[] args)
    {
        Timer t = new Timer(TimerCallback, null,0,2000);
        Console.ReadKey();
    }

    static object timerLock = new object();

    static void TimerCallback(object state)
    {
        int tid = Thread.CurrentThread.ManagedThreadId;
        bool lockTaken = false;
        try
        {
            lockTaken = Monitor.TryEnter(timerLock);
            if (lockTaken)
            {
                Console.WriteLine("[{0:D02}]: Task started", tid);
                Thread.Sleep(3000); // Do the work 
                Console.WriteLine("[{0:D02}]: Task finished", tid);
            }
            else
            {
                Console.WriteLine("[{0:D02}]: Task is already running", tid);
            }
        }
        finally
        {
            if (lockTaken) Monitor.Exit(timerLock);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)