65.9K
CodeProject is changing. Read more.
Home

Locking multiple (up to 2) objects

starIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

1.00/5 (1 vote)

Dec 2, 2011

CPOL
viewsIcon

32482

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.
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:
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