Latch me if you can!

In my first blog post I’ve shown a common UI problem when it comes to event handling and programmatic vs. user-triggered events on the one handside and to infinite loops due to recursive event chains on the other. With event detach/attach and boolean flags I’ve shown two simple solutions which are very common in many development projects. But they have their shortcomings and just don’t feel natural. This blog post shows an alternative which I found simple and beautiful.

Latch to the rescue

Jeremy Miller introduced the Latch design pattern as possible solution for the problem at hand. It’s a tiny beautiful, yet little know solution and the latter is a pitty. A Latch encapsulates the logic of executing an action depending on the current state of the Latch. If the Latch is in „Latched“ state, no action is executed. And actions can be executed inside of the Latch (changing the state to „Latched“), preventing other actions from executing.

Latch #1: Disposing Latch

Before reading Jeremy’s post, I’ve made a sort of Latch pattern for myself. Here the Latch implements IDisposable, and the Latched state is set on creation of the Latch and reset at a call of Dispose(). This allows the application of the using() { } syntax and the Latch state is reset automatically when exceptions occur. The Latch class would look like this:

public class Latch : IDisposable
{
    public bool IsLatched { get; private set; }

    public Latch()
    {
        IsLatched = true;
    }

    public void RunIfNotLatched(Action action)
    {
        if (IsLatched)
            return;

        action();
    }

    public void Dispose()
    {
        IsLatched = false;
    }

    public static Latch Latched
    {
        get { return new Latch(); }
    }
    public static Latch UnLatched
    {
        get { return new Latch { IsLatched = false }; }
    }
}

The RunIfNotLatched() method is just a little helper which executes an action given on the current state of the Latch. The actual application of the Latch in the example code from the previous post is shown here:

public partial class SomeControl : UserControl
{
    // ...

    private Latch _textSetByCodeLatch = Latch.UnLatched;

    private ViewData _viewData;
    public ViewData ViewData
    {
        get { return _viewData; }
        set
        {
            _viewData = value;
            if (value != null)
            {
                using (_textSetByCodeLatch = new Latch())
                {
                    _someTextBox.Text = value.SomeValue;
                }
                // other operations
            }
        }
    }

    private void OnSomeTextBoxTextChanged(object sender, EventArgs e)
    {
        _textSetByCodeLatch.RunIfNotLatched(() =>
        {
            // perform data/view update operations
        });
    }
}

At first sight I liked the using() { } syntax. It frees the application code from manually reseting the Latch to UnLatched state. At second sight I think there could be a cleaner solution. In my Latch implementation the using() { } syntax is kind of misused and could lead to irritations because there is implicit knowledge about the internal functionality of the Latch. Again, the intent is not explicitly revealed.

Latch #2: Boolean Latch

A cleaner solution with explicit methods for running actions inside of the Latch and missing action execution when other actions have entered the Latch could be the following Latch implementation:

public class Latch
{
    public bool IsLatched { get; private set; }

    public void RunLatched(Action action)
    {
        try
        {
            IsLatched = true;
            action();
        }
        finally
        {
            IsLatched = false;
        }
    }

    public void RunIfNotLatched(Action action)
    {
        if (IsLatched)
            return;

        action();
    }
}

Here the basic boolean logic behind matches with the Disposing Latch, but the syntax has changed. The Latch now contains two methods. RunLatched() executes an action inside the Latch and prevents actions from being executed in RunIfNotLatched(). Here’s the usage for this Latch type in our example:

public partial class SomeControl : UserControl
{
    // ...

    private readonly Latch _textSetByCodeLatch = new Latch();

    private ViewData _viewData;
    public ViewData ViewData
    {
        get { return _viewData; }
        set
        {
            _viewData = value;
            if (value != null)
            {
                _textSetByCodeLatch.RunLatched(() =>
                {
                    _someTextBox.Text = value.SomeValue;
                });
                // other operations
            }
        }
    }

    private void OnSomeTextBoxTextChanged(object sender, EventArgs e)
    {
        _textSetByCodeLatch.RunIfNotLatched(() =>
        {
            // perform data/view update operations
        });
    }
}

Now the Latch has a cleaner and more explicit syntax. And like the Disposing Latch it has a clean exception handling mechanism. That’s the good news. With that our Boolean Latch is applicable in most simple scenarios. But not in all! Imagine parallel execution of UI actions. Moreover imagine having two actions which should be run in RunLatched() of the same Latch object – again in parallel:

  1. Action 1 enters RunLatched() and the Latch changes its state.
  2. Action 2 enters RunLatched(), the Latch state remains in IsLatched.
  3. Action 1 leaves RunLatched() and the Latch changes its state to not latched.

Step 3 is the problem. Action 2 is still running inside the Latch, but due to the boolean logic the Latch is not latched any longer. Thus other actions are executed when given to RunIfNotLatched(), which is no help on the initial problem. This is not only true for the Boolean Latch, but for the Disposing Latch as well.

Latch #3: Counting Latch

This problem is solved by the Counting Latch, which is most similar to Jeremy’s Latch implementation. Instead of having just a boolean discriminator, it employs a counter for parallel RunLatched() calls. The IsLatched state is determined based on this counter. If it’s equal to 0, the Latch is not latched (because no method is currently running inside of RunLatched()). Else the Latch is treat as latched. Here’s the implementation of this Latch variant (edit: thanks nwiersma for the thread-safe hint):

public class Latch
{
    private readonly object _counterLock = new object();

    public int LatchCounter { get; private set; }

    public bool IsLatched
    {
        get { return (LatchCounter > 0); }
    }

    public void RunLatched(Action action)
    {
        try
        {
            lock(_counterLock) { LatchCounter++; }
            action();
        }
        finally
        {
            lock(_counterLock) { LatchCounter--; }
        }
    }

    public void RunIfNotLatched(Action action)
    {
        if (IsLatched)
            return;

        action();
    }
}

The usage in this case is equivalent to the Boolean Latch. You should note that each of these Latch implementations works, it’s just a matter of your requirements which of them you want to use. The Counting Latch as most generic Latch implementation above and applies to most situations.

Benefits of using the Latch

Using the Latch for the foresaid problems has clear advantages over the use of event detach/attach and boolean flags. First the Latch encapsulates the logic of running actions depending on a state, in this case the current execution of another action. Thus the purpose of a Latch is explicit, in contrast to the implicit intent of e.g. boolean flags. This increases code readability.

The second advantage comes with resetting the initial state. The Latch performs this task itself when an action leaves the RunLatched() method for example. With boolean flags and event detach/attach this is your task. It’s most likely getting problematic if exceptions are thrown inside an action. The Latch takes over the responsibility of automatically rolling back the state of the Latch on occurrence of an exception.

In conclusion the Latch is a pretty simple design pattern which increases readability and feels right for the problem of dependent action execution. For myself, at least I’ve found some nice solution for UI event reaction depending on the source of the trigger of the event and for infinite event loops, without relying on ugly boolean flags or event attach/detach.

kick it on DotNetKicks.com

7 Gedanken zu „Latch me if you can!“

  1. Awesome article. Just a suggestion though. You should lock the counter in your third solution to make it thread safe. Again, a really good read

  2. Nice to see people doing some re-engineering on this.

    Currently I’m not sure if I would like this (while I like Rx). Can you show a concrete example of the usage?

  3. Hi,

    I agree that this can be a very useful technique. In the past, I’ve used a combination of your approach 1 and approach 3. Basically, you keep a factory object that tracks your latch depth and allocate a new IDisposable whenever you want to create a latched region in your code. I think approach 2 is really dangerous. It makes composition of latched blocks impossible (since the inner-most block will unlatch when it is done).

    As for thread-safety, … sure… you probably want to make your latch thread-safe in case the caller behaves badly with it. You can probably get away with the faster Interlocked increment and decrement operations rather than keeping around a separate object just for locking. On the other hand, if you are touching your latch structures on multiple threads, then this is a good sign that you have a race in your code. I think the latch model implicitly assumes that the latch, observed data structures, and events it protects to always be „owned“ by some thread (e.g. the GUI thread). The common case will be that the user does some action which requires the creation of a latch block before we update some GUI controls. In this case, the creation of the latch block and the GUI updates which may fire the events are all running on the GUI thread, so there is no need to introduce thread-safety. In the other cases, when some freaky worker thread wants to use this functionality, it will need to post (BeginInvoke) onto the owner (GUI) thread before it updates the data structures (controls). The latch block should only be created on this context.

    public class LatchFactory {
    private int count;

    private class LatchBlock : IDisposable {
    private readonly LatchFactory factory;

    public LatchBlock(LatchFactory factory) {
    this.factory=factory;
    }

    public void Dispose() {
    factory.Enable();
    }
    }

    private void Disable() {
    Interlocked.Increment(ref count);
    }

    private void Enable() {
    Interlocked.Decrement(ref count);
    }

    public IDisposable Create() {
    Disable();
    return new LatchBlock(this);
    }

    public bool IsLatched {
    get { return count>0; }
    }

    public void RunIfNotLatched(Action action) {
    if(IsLatched) {
    return;
    }
    action();
    }
    }

    public class Demo {
    private readonly LatchFactory factory=new LatchFactory();

    public void DoSomething() {
    using(factory.Create()) {
    // do some GUI updates which may trigger events
    // we have latched, so events won’t pass through
    }
    }

    public void MyEventHandler() {
    factory.RunIfNotLatched(() => {
    // pass through updates
    });
    }
    }

  4. I used this class in a situation where I had a recursive call that I wanted to latch so it wouldn’t recurse. I effectively wanted to to nest a RunLatched() call inside of a RunIfNotLatched() call. Then, I realised I could achieve the same by simply adding the following to the start of RunLatched():

    if (IsLatched) return;

    Simples! Is there anything fundamentally wrong with this? I don’t know why it wasn’t there in the first place; or, does it mess up the examples given?

Kommentare sind geschlossen.