2

I need to implement simple function that is called from multiple threads. The logic of the function is simple - think of horse races - only the first horse can get golden medal once we have a winner the race is over.

class ConditionalOrderGroup
{
    private volatile bool _locked = false;
    private List<ConditionalOrder> _ConditionalOrderList = null;        

public bool LockGroup(ConditionalOrder initiator)
{
   // this is finishline - we need to let only the first one proceed
    if (_locked)
        return false;
    else
    {
        _locked = true;
    }

    // this is what winner gets
    foreach (ConditionalOrder order in _ConditionalOrderList)
    {

      \\ cancel other orders
    }

    return true;
}
}

I am not happy with

if (_locked)
    return false;
else
{
    _locked = true;
}

What if two orders can pass if check and proceed to else. How to rewrite this code without using lock statement?

UPDATE I mean my goal is not use any blocking method like lock statement.

3 Answers 3

2

You need a separate, private object and use the built-in locking:

private object padLock = new object();  // 1-to-1 with _ConditionalOrderList

if (Monitor.TryEnter(padLock))
{
   try 
   {
      // cancel other orders

      return true;
   } 
   finally 
   {
       Monitor.Exit(padLock);
   }
}
else
{
   return false;
}
Sign up to request clarification or add additional context in comments.

5 Comments

Great! This just what I need a non-blocking method.
@Martin: He said without the lock statement. What he already does is a (although crude) lock in itself.
@Martin: TryEnter is lock-if-you-can w/o blocking.
If you're going to go this route, you want to wrap Try/Finally statements around everything inside the lock success case, and put Monitor.Exit(padLock) in the finally. Assuming you ever want to release the lock, which is probably a fair assumption ;)
Monitor.Exit(), not Monitor.Leave()
1

Use Interlocked class to change values of the variable in a thread safe way.

Comments

1

Expanding on what decyclone said about interlocked, this is exactly how you would do it:

const int LOCKED = 1;
const int UNLOCKED = 0;

volatile int lockState = UNLOCKED;

public bool Foo()
{
    try
    {
        //locking
        //compare exchange returns the value that was in lockState before the compareExchange operation, so from that you can determine if you grabbed the lock or not
        //if it was locked before, then you know the lock is not yours
        if (Interlocked.CompareExchange(ref lockState, UNLOCKED, LOCKED) == LOCKED)
            return false;

        //lock is yours, do whatever stuff you like here, including throw exceptions
    }
    finally
    {
        //unlocking
        //because this is in finally this lock will be released even if something goes wrong with your code
        Interlocked.Exchange(ref lockstate, UNLOCKED);
    }
}

1 Comment

Yes, but this is a crude approximation of what the Monitor class does. I rather put my trust in a BCL class if I can. Especially when it comes to parallelism.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.