Stopping timer in its callback method

前端 未结 5 946
逝去的感伤
逝去的感伤 2020-12-05 01:23

I have a System.Threading.Timer that calls its appropriate event handler (callback) every 10 ms. The method itself is not reentrant and can

5条回答
  •  囚心锁ツ
    2020-12-05 01:47

    A couple possible solutions:

    • have the real work done in yet another thread delegate that's waiting on an event. The timer callback merely signals the event. The worker thread cannot be reentered, as it's a single thread that does its work only when the event is signaled. The timer is reentrant, since all it does is signal the event (seems a little roundabout and wasteful, but it'll work)
    • have the timer created with only a start timeout and no periodic timeout so it'll fire only once. The timer callback will dispose of that timer object and create a new one when it has completed its work that will also only fire once.

    You may be able to manage option #2 without disposing/creating a new object by using the Change() method of the original timer object, but I'm not sure what the behavior is exactly of calling Change() with a new start timeout after the first timeout has expired. That would be worth a test or two.

    Edit:


    I did the test - manipulating the timer as a restartable one-shot seems to work perfectly, and it's much simpler than the other methods. Here's some sample code based on yours as a starting point (a few details may have changed to get it to compile on my machine):

    private Timer _creatorTimer;
    
    // BackgroundWorker's work
    private void CreatorWork(object sender, EventArgs e) {
        // note: there's only a start timeout, and no repeat timeout
        //   so this will fire only once
        _creatorTimer = new Timer(CreatorLoop, null, 1000, Timeout.Infinite);
    
        // some other code that worker is doing while the timer is active
        // ...
        // ...
    }
    
    private void CreatorLoop(object state) {
        Console.WriteLine( "In CreatorLoop...");
        /*
            ... Work here
        */
        Thread.Sleep( 3000);
    
        // Reenable timer
        Console.WriteLine( "Exiting...");
    
        // now we reset the timer's start time, so it'll fire again
        //   there's no chance of reentrancy, except for actually
        //   exiting the method (and there's no danger even if that
        //   happens because it's safe at this point).
        _creatorTimer.Change(1000, Timeout.Infinite);
    }
    

提交回复
热议问题