views:

113

answers:

4

Hi;

When implementing a thread safe list or queue; does it requaired to lock on List.Count property before returning the Count i.e:

//...
public int Count 
{
    lock (_syncObject)
    {
       return _list.Count;
    }
}
//...

is it nessesary to do a lock because of the original _list.Count variable maybe not a volatile variable?

Thanks in advanced.

+5  A: 

Yes, that is necessary, but mostly irrelevant. Without the lock you could be reading stale values or even, depending on the inner working and the type of _list.Count, introduce errors.

But note that using that Count property is problematic, any calling code cannot really rely on it:

if (myStore.Count > 0)  // this Count's getter  locks internally 
{
    var item = myStore.Dequeue(); // not safe, myStore could be empty
}

So you should aim for a design where checking the Count and acting on it are combined:

ItemType GetNullOrFirst()
{
    lock (_syncObject)
    {
       if (_list.Count > 0)
       {
           ....
       }
    }
}

Additional:

is it nessesary to do a lock because of the original _list.Count variable maybe not a volatile variable?

The _list.Count is not a variable but a property. It cannot be marked volatile. Whether it is thread-safe depends on the getter code of the property, but it will usually be safe. But unreliable.

Henk Holterman
@Jalal, on second thought, you probably can just read it. It just doesn't mean very much. I think the second part of my answer is the most relevant. See for instance the remarks here: http://msdn.microsoft.com/en-us/library/dd267246.aspx
Henk Holterman
@Henk; thank you for your responce.. I know that the _list.Count is a property but I meant the original value that will be returned "from _list.Count get accessor" when calling the _list.Count,like the variable _count or _size "you can see it throw Visual Studio IDE debugger insert break point to the list and see its 'Non_Public members' for a List<int> you will see the variable _size that conatins the count". that variable may not marked as volatile..
Jalal Aldeen Saa'd
+2  A: 

It depends.

Now, theoretically, because the underlying value is not threadsafe, just about anything could go wrong because of something the implementation does. In practice though, it's a read from a variable of 32-bits and so guaranteed to be atomic. Hence it might be stale, but it will be a real stale value rather than garbage caused by reading half a value before a change and the other half after it.

So the question is, does staleness matter? Possibly it doesn't. The more you can put up with staleness the better for performance (because the more you can put up with it the less you need to do to ensure you don't have anything stale). E.g. if you were putting the count out to the UI and the collection was changing rapidly, then just the time it takes for the person to read the number and process it in their own brain is going to be enough to make it obsolete anyway, and hence stale.

If however, you needed it to ensure an operation was reasonable before it was attempted, then that staleness is going to cause problems.

However, that staleness is going to happen anyway, because in between your locked (and guaranteed to be fresh) read and the operation happening, there's the opportunity for the collection to change, so you've got a race condition even when locking.

Hence, if freshness is important, you are going to have to lock at a higher level. With this being the case, the lower-level lock is just a waste. Hence you can probably do without it at that point.

The important thing here is that even with a class that is threadsafe in every regard, the best that can guarantee is that each operation will be fresh (though even that may not be guaranteed; indeed when there are more than one core involved "fresh" begins to become meaningless as changes that are near to truly simultaneous can happen) and that each operation won't put the object into an invalid safe. It is still possible to write non-threadsafe code with threadsafe objects (indeed very many non-threadsafe objects are composed of ints, strings and bools or objects that are in turn composed of them, and each of those is threadsafe in and of itself).

One thing that can be useful with mutable classes intended for multithreaded use are synchronised "Try" methods. E.g. to use a List as a stack we need the following operations:

  1. See if the list is empty, reporting failure if it is.
  2. Obtain the "top" value.
  3. Remove the top value.

Even if we synchronise each of those individually, the code doing so won't be threadsafe as something can happen between each step. However, we can provide a Pop() method that does each three in one synchronised method. Analogous approaches are also useful with lock-free classes (where different techniques are used to ensure the method either succeeds or fails completely, and without damage to the object).

Jon Hanna
+2  A: 

No, you don't need to lock, but the caller should otherwise something like this might happen

count is n
thread asks for count
Count returns n
another thread dequeues
count is n - 1
thread asking for count sees count is n when count is actually n - 1
Jason
If you using lock as above (in the question) you just improve the chance of true answer, there will be a time between calling count, and then going to lock, and you have a same senario
SaeedAlg
@SaeedAlg; that is true; we are improve the change of true answer but the lock it self has a cost.. so if we can avoid it way not..
Jalal Aldeen Saa'd
A: 

I think its better to use monitor for this case.

SaeedAlg
What do you mean by using Monitor? I am using monitor; lock "as you know" is: Monitor.Enter(valueToLock) try {//here is the user code} finaly {Monitor.Exit(valueToLock);}
Jalal Aldeen Saa'd
@Jalal Aldeen Saa'd, If the lock and monitor were a same thing why Microsoft introduces monitor and so on, you can use monitor to lock on the object that you want work on it, but in lock, first you calling the object and then using lock to do the action, you can implement monitor by lock but your current code doesn't say anything about this implementation.
SaeedAlg
Also using lock to implement monitor is a wrong way when you have abstract implementation like monitor.
SaeedAlg
@Saeed; "If the lock and monitor were a same thing why Microsoft introduces monitor" the lock is a shortcut for the folowing: Monitor.Enter(valueToLock)try{//code}finally{Monitor.Exit(valueToLock);} see http://www.albahari.com/threading/part2.aspx. "Also using lock to implement monitor is a wrong way when you have abstract implementation like monitor" may be I don't understand what your point here but no! that is not right.. the lock statement is infact a shortcut for Monitor.Enter and Monitor.Exit so I am using the Monitor shortcut what is the wrong with That!...
Jalal Aldeen Saa'd
@Jalal Aldeen Saa'd,No its not shortcut ,I didn't read your reference site.I'll read it tomorrow ,but I left the reference to MSDN,read it(code) carefully,I'm not fluent in English MSDN tells details.
SaeedAlg
Jalal is right here, the official definition of `lock() {}` is a rewrite using `Monitor` and `try/finally`.
Henk Holterman
@ Henk Holterman, monitor is an `abstraction` of lock not a `shortcut` or something like this, how can i show it to you when you reading the MSDN, and seeing its sample and now saying this?
SaeedAlg
Monitor is _not_ an abstraction, it is a very concrete library class. A `lock` statement is rewritten just like jalal indicated.
Henk Holterman
Ok, you are right.
SaeedAlg
@Henk Holterman, But at all non of the solutions provided here are useful for protecting from bad manners which are described in solutions.
SaeedAlg