简体   繁体   中英

Is there a way to prevent an event handler from firing over itself?

I have an event handler for an event that can occur in rapid succession. In some cases, the handler will still be executing when the event fires again (within milliseconds).

Is there anyway to make these handlers...serial? So, Event Invocation #2 cannot start until Event Invocation #1 has completed?

If this is an awful idea, why? This is a batch process that runs unattended in the background, so I'm not terribly concerned about performance issues that might occur from one invocation blocking another.

Use the mult-thread controle lock . This prevents that your code will be run more the one time in same moment.

EDITED
EXAMPLE:

public class Foo
{
    private static object _lockKey = new object();

    private void YourEventHandlerMethod(object sender, EventArgs e)
    {   
        lock (_lockKey)
        {
            // the code you put inside this block will be execute only
            // once at time.

            // If a second call has the intention to use this block before
            // the conclusion of the first call, the second call (the thread)
            // will be put in hold.
        }
    }
}

There are a few options to serialize handling of the events which may be fired concurrently from multiple threads, or on the same thread via re-enrancy/recursion.

One of the options is to use a task scheduler. In your scenario, the purpose of the task scheduler would be to queue callbacks for later serial execution. A well known conceptual examples of the task schedulers like that are WinForms message loop (starting with Application.Run , queuing with Control.BeginInvoke ) and WPF Dispatcher loop (starting with Dispatcher.Run , queuing with Dispatcher.BeginInvoke or Dispatcher.InvokeAsync ).

A less know but very useful implementation of a TPL task scheduler is StaTaskScheduler by Stephen Toub. I posted some code based upon it here and here (the latter one is from a closely question, Queuing Actions/Delegates for Asyncronous Execution ).

Another option is described here: Task sequencing and re-entracy .

In this case, handlers are composed as tasks, each new handler is started when the previous task has completed.

Eight years down the road, I've discovered the joy of the blocking collection.

Instead of having the event handler do the work, I could have just put some data in a blocking collection and had a separate thread to work that.

private readonly BlockingCollection<Whatever> queue = new BlockingCollection<Whatever>();

Task.Run(() =>
{
  while (!queue.IsCompleted) {

   // Do whatever

  }
}

// Then just add a bunch of stuff to it
queue.Add(new Whatever());

// It will just keep working the queue in a separate thread, going back for a new Whatever whenever it's done

// You can even start multiple threads to work the queue. They won't interfere with each other

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM