views:

101

answers:

3

Hi

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.

+2  A: 

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;
}
Henk Holterman
He said without using locks.
Martin
Great! This just what I need a non-blocking method.
Captain Comic
@Martin: He said without the *lock statement*. What he already does is a (although crude) lock in itself.
mizipzor
@Martin: TryEnter is lock-if-you-can w/o blocking.
Henk Holterman
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 ;)
Martin
@MartinL yes, now that you mention it...
Henk Holterman
Monitor.Exit(), not Monitor.Leave()
Captain Comic
+1  A: 

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

decyclone
+1  A: 

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);
    }
}
Martin
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.
Henk Holterman