Interlocked used to increment/mimick a boolean, is this safe?

Sarah Fordington picture Sarah Fordington · Sep 7, 2009 · Viewed 8.5k times · Source

I'm just wondering whether this code that a fellow developer (who has since left) is OK, I think he wanted to avoid putting a lock. Is there a performance difference between this and just using a straight forward lock?

    private long m_LayoutSuspended = 0;
    public void SuspendLayout()
    {
        Interlocked.Exchange(ref m_LayoutSuspended, 1);
    }

    public void ResumeLayout()
    {
        Interlocked.Exchange(ref m_LayoutSuspended, 0);
    }

    public bool IsLayoutSuspended
    {
        get { return Interlocked.Read(ref m_LayoutSuspended) != 1; }
    }

I was thinking that something like that would be easier with a lock? It will indeed be used by multiple threads, hence why the use of locking/interlocked was decided.

Answer

Pop Catalin picture Pop Catalin · Sep 7, 2009

Yes what you are doing is safe from a race point of view reaching the m_LayoutSuspended field, however, a lock is required for the following reason if the code does the following:

if (!o.IsLayoutSuspended)  // This is not thread Safe .....
{
  o.SuspendLayout();   // This is not thread Safe, because there's a difference between the checck and the actual write of the variable a race might occur.
  ...
  o.ResumeLayout();
} 

A safer way, that uses CompareExchange to make sure no race conditions have occurred:

private long m_LayoutSuspended = 0;
public bool SuspendLayout()
{
    return Interlocked.CompareExchange(ref m_LayoutSuspended, 1) == 0;
}

if (o.SuspendLayout()) 
{
  ....
  o.ResumeLayout();
}

Or better yet simply use a lock.