Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/299.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用带线程的锁。计时器_C#_Multithreading_Locking - Fatal编程技术网

C# 使用带线程的锁。计时器

C# 使用带线程的锁。计时器,c#,multithreading,locking,C#,Multithreading,Locking,我有一个Windows服务应用程序,它使用Threading.Timer和TimerCallback以特定的间隔执行一些处理。我需要将这个处理代码一次只锁定到一个线程 例如,启动服务并触发第一个回调,启动线程并开始处理。只要处理在下一次回调之前完成,这就可以正常工作。比如说,处理时间比平常稍长,当另一个线程正在处理时,TimerCallback会再次触发,我需要让该线程等待,直到另一个线程完成 以下是我的代码示例: static Timer timer; static object locker

我有一个Windows服务应用程序,它使用
Threading.Timer
TimerCallback
以特定的间隔执行一些处理。我需要将这个处理代码一次只锁定到一个线程

例如,启动服务并触发第一个回调,启动线程并开始处理。只要处理在下一次回调之前完成,这就可以正常工作。比如说,处理时间比平常稍长,当另一个线程正在处理时,TimerCallback会再次触发,我需要让该线程等待,直到另一个线程完成

以下是我的代码示例:

static Timer timer;
static object locker = new object();

public void Start()
{
    var callback = new TimerCallback(DoSomething);
    timer = new Timer(callback, null, 0, 10000);
}

public void DoSomething()
{
      lock(locker)
      {
           // my processing code
      }
}

这样做安全吗?如果队列变得相当多,会发生什么?有更好的选择吗?

如果可以让事件以固定的间隔触发(与当前代码以固定的间隔触发相反),那么您可以启动计时器,而无需使用句点,每次都可以排队等待新的回调,例如

static Timer timer;

public void Start()
{
    var callback = new TimerCallback(DoSomething);
    timer = new Timer(callback, null, 0, Timeout.Infinite);
}

public void DoSomething()
{
      try
      {
           // my processing code
      }
      finally
      {
          timer.Change(10000, Timeout.Infinite);
      }
}
此代码告诉新创建的计时器立即启动,仅启动一次。在处理代码中,它完成工作,然后告诉计时器在10秒内再次启动,仅一次。由于计时器现在不定期启动,而是通过其回调方法重新启动,因此回调保证是单线程的,没有队列

如果你想保持一个恒定的时间间隔,那么这就有点棘手了,因为如果处理开始花费的时间超过计时器的时间间隔,你必须决定该怎么做。一种选择是执行您当前正在执行的操作,但最终会导致大量排队线程,并最终导致线程池不足。另一种选择是,如果已经有回调在进行中,只需放弃回调,例如

static Timer timer;
static object locker = new object();

public void Start()
{
    var callback = new TimerCallback(DoSomething);
    timer = new Timer(callback, null, 0, 10000);
}

public void DoSomething()
{
      if (Monitor.TryEnter(locker))
      {
           try
           {
               // my processing code
           }
           finally
           {
               Monitor.Exit(locker);
           }
      }
}

如果处理代码的执行时间超过10秒,则最糟糕的情况是每次调用新回调时都会浪费1个线程池线程(它们将在lock语句中等待)。如果您接受所有线程池线程HttpWebRequest、ASP.NET、异步委托调用。。。我会受苦的

我要做的是立即安排第一次回调。然后,如果确实需要每隔10秒调用DoSomething():

public void DoSomething ()
{
       DateTime start = DateTime.UtcNow;
       ...
       TimeSpan elapsed = (DateTime.UtcNow - start);
       int due_in = (int) (10000 - elapsed.TotalMilliseconds);
       if (due_in < 0)
           due_in = 0;
       timer.Change (due_in, Timeout.Infinite);
}
public void DoSomething()
{
DateTime start=DateTime.UtcNow;
...
时间跨度经过=(DateTime.UtcNow-start);
int due_in=(int)(10000-已用的.total毫秒);
如果(到期日<0)
到期日=0;
timer.Change(到期,超时,无限);
}

或者类似的东西。

触发计时器的好主意从来没有这样想过。第二种情况,这是否意味着线程只是退出而不等待?是的,在第二种情况下,如果当前处理代码中有另一个线程,TryEnter将立即返回,因此它有效地跳过了该计时器间隔。太好了!我使用的是JavaScript中的第一个场景。不知道如何在C#中实现它。