只有在前一个事件完成时才提出事件

时间:2014-05-15 16:02:44

标签: c# timer

我在我的应用程序中使用System.Timers.Timer。每一秒我都会运行一个能完成某项工作的功能。问题是,这个函数可以阻塞一段时间(它读取然后从磁盘处理一个大文件)。我想只在其先前的"执行实例"已经完成了。我以为我可以通过Mutex

实现这一目标
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        static Mutex TimerMut = new Mutex(false);
        public static void Main()
        {

            Thread TT = new Thread(new ThreadStart(delegate()
            {
                System.Timers.Timer oTimer = new System.Timers.Timer();
                oTimer.Elapsed += new ElapsedEventHandler(Handler);

                oTimer.Interval = 1000;
                oTimer.Enabled = true;
            }));

            TT.Start();

            Console.Read();
        }

        private static void Handler(object oSource,
            ElapsedEventArgs oElapsedEventArgs)
        {
            TimerMut.WaitOne();
            Console.WriteLine("foo");
            Thread.Sleep(500);         //simulate some work
            Console.WriteLine("bar");
            TimerMut.ReleaseMutex();
        }
    }
}

那不起作用," foos"仍然每秒出现。我怎样才能做到这一点?

编辑:你是对的,开始一个新的线程来处理它是没有意义的。我以为只有System.Threading.Timer在一个单独的线程中启动。

4 个答案:

答案 0 :(得分:2)

如果你想跳过勾选,如果另一个已经工作,你可以这样做。

private readonly object padlock = new object();

private void SomeMethod()
{
    if(!Monitor.TryEnter(padlock))
        return;

    try
    {
        //Do heavy work
    }
    finally
    {
        Monitor.Exit(padlock);
    }
}

答案 1 :(得分:1)

如果此方法的另一次调用仍在运行,您可以按照以下模式跳过执行指定的工作:

private int isWorking = 0;
public void Foo()
{
    if (Interlocked.Exchange(ref isWorking, 1) == 0)
    {
        try
        {
            //Do work
        }
        finally
        {
            Interlocked.Exchange(ref isWorking, 0);
        }
    }
}

您使用Mutex的方法将导致额外的滴答等待更早的滴答完成,而不是在另一个仍在运行时跳过调用 ,这就是你说的你想要的。 (当处理这样的计时器时,常见的是想要跳过这样的刻度,而不是等待。如果你的刻度处理程序经常花费太长时间,你会得到一个巨大的等待处理程序队列。)

答案 2 :(得分:0)

我不确定你为什么要使用新线程来启动计时器,因为计时器在他们自己的线程上运行,但这是一个有效的方法。只需关闭计时器,直到完成当前间隔。

static System.Timers.Timer oTimer

public static void Main()
{
    oTimer = new System.Timers.Timer();
    oTimer.Elapsed += new ElapsedEventHandler(Handler);

    oTimer.Interval = 1000;
    oTimer.Enabled = true;                 
}

private void Handler(object oSource, ElapsedEventArgs oElapsedEventArgs)
{
    oTimer.Enabled = false;

    Console.WriteLine("foo");
    Thread.Sleep(5000);         //simulate some work
    Console.WriteLine("bar");

    oTimer.Enabled = true;
}

答案 3 :(得分:0)

我知道做这种事情的最简单方法:

internal static volatile bool isRunning;

public static void Main()
    {
        Thread TT = new Thread(new ThreadStart(delegate()
            {
                System.Timers.Timer oTimer = new System.Timers.Timer();
                oTimer.Elapsed += new ElapsedEventHandler(Handler);

                oTimer.Interval = 1000;
                oTimer.Enabled = true;                 
            }));

        TT.Start();
    }

    private void Handler(object oSource,
        ElapsedEventArgs oElapsedEventArgs)
    {
        if(isRunning) return;

        isRunning = true;

        try
        {
           Console.WriteLine("foo");
           Thread.Sleep(500);         //simulate some work
           Console.WriteLine("bar");
        }
        finally { isRunning = false; }            
    }

处理程序仍然运行,但它首先要确保另一个处理程序没有运行,如果是,它会立即停止。

对于更快速执行处理程序的计时器(例如每秒3-4次),这有可能比赛;在其中一个线程设置位之前,两个线程可以继续执行保护子句。您可以使用几个lock语句来避免这种情况,类似于Mutex或Monitor:

    static object syncObj = new object();

    private void Handler(object oSource,
        ElapsedEventArgs oElapsedEventArgs)
    {
        lock(syncObj)
        {
           if(isRunning) return;            
           isRunning = true;
        }

        try
        {
           Console.WriteLine("foo");
           Thread.Sleep(500);         //simulate some work
           Console.WriteLine("bar");
        }
        finally { lock(syncObj) { isRunning = false; } }            
    }

这将确保只有一个线程可以检查或修改isRunning,并且因为isRunning被标记为volatile,所以CLR不会将其值缓存为每个线程的性能状态的一部分;每个线程必须查看完全相同的内存位置以检查或更改值。