Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / programming / threads

Locking multiple (up to 2) objects

1.00/5 (1 vote)
25 Dec 2011CPOL 32.5K  
Lock multiple (up to 2) objects, non blocking
This was needed due to the fact that I needed to obtain locks to multiple objects (stating the obvious) (How to say this in a more interesting way?).

Anyway, if you ever need to lock 2 objects, and are not sure if they are null or not, then try the next code.

This approach will not block and lock both, when 2 non null references are given, or none. It will wait until both are locked, or 1000ms passed.

After 1000ms, default, timeout the DuoEnter method will throw a timeout exception.

C#
internal static void DuoEnter(object po1, object po2, int pnTimeOutMs = 1000)
{
    if ((po1 == null) && (po2 == null))
        return;
    int nMaxLoops = 100 * pnTimeOutMs;
    bool lOneProcessor = Environment.ProcessorCount < 2;
    for (int nLoops = 0; nLoops < nMaxLoops; nLoops++)
    {
        if ((po1 == null) || (po2 == null) || (po1 == po2))
        {
            if (Monitor.TryEnter(po1 ?? po2))
                return;
        }
        else
        {
            if (Monitor.TryEnter(po1))
                if (Monitor.TryEnter(po2))
                    return;
                else
                    Monitor.Exit(po1);
        }
        if (lOneProcessor || (nLoops % 100) == 99)
            Thread.Sleep(1); // Never use Thread.Sleep(0)
        else
            Thread.SpinWait(20);
    }
    throw new TimeoutException(
        "Waited more than 1000 mS trying to obtain locks on po1 and po2");
}

internal static void DuoExit(object po1, object po2)
{
    if ((po1 == null) && (po2 == null))
        return;
    if (po1 == null || po2 == null || po1 == po2)
        Monitor.Exit(po2 ?? po1);
    else
    {
        Monitor.Exit(po2);
        Monitor.Exit(po1);
    }
}


Use it as in:

C#
internal void InternalDispose()
{
    List<TreeCachedNodeInfo> aoTreeCachedNodeInfoList
        = this._aoTreeCachedNodeInfoList;
    List<Node> aoNodeList
        = this._aoNodeList;
    DuoEnter(aoNodeList, aoTreeCachedNodeInfoList);
    try
    {
        if (aoNodeList != this._aoNodeList)
            throw new InvalidOperationException(
                "aoNodeList != this._aoNodeList");
        if (aoTreeCachedNodeInfoList != this._aoTreeCachedNodeInfoList)
            throw new InvalidOperationException(
                "aoTreeCachedNodeInfoList != this._aoTreeCachedNodeInfoList");
        if (aoNodeList != null)
        {
            this._aoNodeList = null;
            aoNodeList.Clear();
        }
        if (aoTreeCachedNodeInfoList != null)
        {
            this._aoTreeCachedNodeInfoList = null;
            aoTreeCachedNodeInfoList.Clear();
        }
    }
    finally
    {
        DuoExit(aoNodeList, aoTreeCachedNodeInfoList);
    }
}

That's all, I hope you like it.

Regards,

Frans de Wit

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)