Is there a difference in the below code segments in the way we lock?
public Hashtable mySet= new Hashtable() //mySet is visible to other threads.
lock (mySet)
{
mySet.Add("Hello World");
}
and
public Hashtable mySet= new Hashtable();
lock(mySet.SyncRoot)
{
mySet.Add("Hello World");
}
lock doesn't actually lock the object in question, so it makes no difference which object is used. Instead it uses the object to establish a protocol and as long as all threads use the same object the protocol guarantees that only one thread will execute code guarded by that lock.
You can think of the object as the microphone on a talk show. Whoever holds the microphone is the only one allowed to talk (I know that is not always how it turns out on some of the shows, but that's the idea anyway).
As the object passend to the lock will only be used as a "flag holder", this will not make any difference.
Please see this
According to the MSDN documentation here only a lock on the SyncRoot of a collection does guarantee thread safety.
Enumerating through a collection is intrinsically not a thread-safe
procedure. Even when a collection is synchronized, other threads can
still modify the collection, which causes the enumerator to throw an
exception. To guarantee thread safety during enumeration, you can
either lock the collection during the entire enumeration or catch the
exceptions resulting from changes made by other threads.
Related
Please explain the difference between these two types of locking.
I have a List which I want to access thread-safe:
var tasks = new List<string>();
1.
var locker = new object();
lock (locker)
{
tasks.Add("work 1");
}
2.
lock (tasks)
{
tasks.Add("work 2");
}
My thoughts:
Prevents two different threads from running the locked block of code at the same time.
But if another thread runs a different method where it tries to access task - this type of lock won't help.
Blocks the List<> instance so other threads in other methods will be blocked untill I unlock tasks.
Am I right or mistaking?
(2) only blocks other code that explicitly calls lock (tasks). Generally, you should only do this if you know that tasks is a private field and thus can enforce throughout your class that lock (tasks) means locking operations on the list. This can be a nice shortcut when the lock is conceptually linked with access to the collection and you don't need to worry about public exposure of the lock. You don't get this 'for free', though; it needs to be explicitly used just like locking on any other object.
They do the same thing. Any other code that tries to modify the list without locking the same object will cause potential race conditions.
A better way might be to encapsulate the list in another object that obtains a lock before doing any operations on the underlying list and then any other code can simple call methods on the wrapper object without worrying about obtaining the lock.
If a Queue is syncronized:
var _item = Queue.Synchronized(new Queue());
can I call methods like Enqueue and Dequeue on it without using lock statements?
My current code is:
lock (_item.SyncRoot)
{
_item.Enqueue(obj);
}
Can I thread-safely use:
_item.Enqueue(obj);
var item = _item.Dequeue();
The call to Enqueue and the call to Dequeue are thread safe.
However, your sample code is not:
Between the call to Enqueue and the call to Dequeue there could have been a thread switch. This means, that item might be another instance than obj or the call to Dequeue throws an exception, because it now is empty.
To make your sample code thread safe, you still need to lock explicitly:
lock(_item.SyncRoot)
{
_item.Enqueue(obj);
var item = _item.Dequeue);
}
Only now it is guaranteed, that item reference-equals obj in all circumstances.
That is pretty much what SynchronizedQueue does, but there is a problem... typically you need to check the .Count and .Dequeue() in one atomic unit - not check the .Count (one unit) then .Dequeue() (another unit) - you can't trust .Count at all once the lock is surrendered, and .Dequeue() will throw if another thread has stolen the work.
Maybe try ConcurrentQueue<T> in 4.0 (with .TryDequeue()), or use Queue<T> and lock.
From MSDN
To guarantee the thread safety of the
Queue, all operations must be done
through this wrapper only.
Enumerating through a collection is
intrinsically not a thread-safe
procedure. Even when a collection is
synchronized, other threads can still
modify the collection, which causes
the enumerator to throw an exception.
To guarantee thread safety during
enumeration, you can either lock the
collection during the entire
enumeration or catch the exceptions
resulting from changes made by other
threads.
Just as John Skeet's answer suggests here, you might be better or using locking since enumerating might cause an exception.
Gregs answer also talks about what Marc mentions with the Count not being thread safe.
I have a Dictionary that tracks objects (ClientObject). Both the dictionary and ClientObject's are accessed by multiple threads. When I modify or read any object in this dictionary, I obtain a read or write lock on the dictionary using ReaderWriterLockSlim (rwl_clients) then obtain an exclusive lock on the actual object.
I just wanted to know if I am using these .net threading facilities correctly
Example:
rwl_clients.EnterReadLock();
ClientObject clobj;
if(!m_clients.TryGetValue(key, out clobj))
return;
rwl_clients.ExitReadLock();
SomeMethod(clobj);
SomeMethod(ClientObject clobj) would do something like:
lock(clobj) {
/// Read / Write operations on clobj
}
Does getting and locking a value (ClientObject) from the dictionary in one thread mean that other threads will respect that lock? In other words, does .net see a value in the dictionary as a single resource (and not a copy) and will therefore respect a lock on that resource in all threads?
One more question, when removing a resource from the dictionary - should I lock it before performing Remove()
Example:
rwl_clients.EnterWriteLock();
ClientObject clobj;
if(m_clients.TryGetValue(key, out clobj)) {
lock(clobj) {
m_clients.Remove(key);
}
}
rwl_clients.ExitWriteLock();
I have learned so much from this site and appreciate any responses!
Thanks.
Does getting and locking a value (ClientObject) from the dictionary in one thread mean that other threads will respect that lock? In other words, does .net see a value in the dictionary as a single resource (and not a copy) and will therefore respect a lock on that resource in all threads?
It depends on the type - if a reference type then yes, if a value type no. This is also why you should never, ever lock on a value type since the value type will be boxed and any subsequent attempts to lock on that value will actually acquire a lock on a different object.
One more question, when removing a resource from the dictionary - should I lock it before performing Remove()
Yes, you should lock before any operation that mutates the state of the object.
As a side note - are you sure that this setup is the best possible solution to your problem? Mutable objects shared across threads tend to create more problems then they solve.
If you are adding or removing items from the dictionary, lock the dictionary.
When you put an object in the dictionary, you are putting a REFERENCE to that object in the dictionary. To prevent that object from being changed by a second thread while the first thread is in the process of changing it, lock the object, not the dictionary.
In the following code:
public class StringCache
{
private readonly object lockobj = new object();
private readonly Dictionary<int, string> cache = new Dictionary<int, string>();
public string GetMemberInfo(int key)
{
if (cache.ContainsKey(key))
return cache[key];
lock (lockobj)
{
if (!cache.ContainsKey(key))
cache[key] = GetString(key);
}
return cache[key];
}
private static string GetString(int key)
{
return "Not Important";
}
}
1) Is ContainsKey thread safe? IOW, what happens if that method is executing when another thread is adding something to the dictionary?
2) For the first return cache[key], is there any chance that it could return a garbled value?
TIA,
MB
The inherent thread safety of ContainsKey doesn't matter, since there is no synchronization between ContainsKey & cache[key].
For example:
if (cache.ContainsKey(key))
// Switch to another thread, which deletes the key.
return cache[key];
MSDN is pretty clear on this point:
To allow the collection to be accessed
by multiple threads for reading and
writing, you must implement your own
synchronization.
For more info, JaredPar posted a great blog entry at http://blogs.msdn.com/jaredpar/archive/2009/02/11/why-are-thread-safe-collections-so-hard.aspx on thread-safe collections.
No, ContainsKey is not thread-safe if you're writing values while you're trying to read.
Yes, there is a chance you could get back invalid results -- but you'll probably start seeing exceptions first.
Take a look at the ReaderWriterLockSlim for locking in situations like this -- it's built to do this kind of stuff.
Here's what it says in the MSDN documentation:
Public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.
A Dictionary<(Of <(TKey, TValue>)>)
can support multiple readers
concurrently, as long as the
collection is not modified. Even so,
enumerating through a collection is
intrinsically not a thread-safe
procedure. In the rare case where an
enumeration contends with write
accesses, the collection must be
locked during the entire enumeration.
To allow the collection to be accessed
by multiple threads for reading and
writing, you must implement your own
synchronization.
If I'm reading that correctly, I don't believe that it is thread safe.
Dictionary is not Thread-Safe.
If you say that
what happens if that method is
executing when another thread is
adding something to the dictionary?
then I suppose other functions access the cache as well. You need to synchronize accesses(reading and writing) to the cache. Use your lock object in all of these operations.
I believe its not thread safe,
I would suggest go thru below link, it shows implementation of the thread safe dictionary, or its better to develop your own synchronization.
http://lysaghtn.weebly.com/synchronised-dictionary.html
I have a Queue object that I need to ensure is thread-safe. Would it be better to use a lock object like this:
lock(myLockObject)
{
//do stuff with the queue
}
Or is it recommended to use Queue.Synchronized like this:
Queue.Synchronized(myQueue).whatever_i_want_to_do();
From reading the MSDN docs it says I should use Queue.Synchronized to make it thread-safe, but then it gives an example using a lock object. From the MSDN article:
To guarantee the thread safety of the
Queue, all operations must be done
through this wrapper only.
Enumerating through a collection is
intrinsically not a thread-safe
procedure. Even when a collection is
synchronized, other threads can still
modify the collection, which causes
the enumerator to throw an exception.
To guarantee thread safety during
enumeration, you can either lock the
collection during the entire
enumeration or catch the exceptions
resulting from changes made by other
threads.
If calling Synchronized() doesn't ensure thread-safety what's the point of it? Am I missing something here?
Personally I always prefer locking. It means that you get to decide the granularity. If you just rely on the Synchronized wrapper, each individual operation is synchronized but if you ever need to do more than one thing (e.g. iterating over the whole collection) you need to lock anyway. In the interests of simplicity, I prefer to just have one thing to remember - lock appropriately!
EDIT: As noted in comments, if you can use higher level abstractions, that's great. And if you do use locking, be careful with it - document what you expect to be locked where, and acquire/release locks for as short a period as possible (more for correctness than performance). Avoid calling into unknown code while holding a lock, avoid nested locks etc.
In .NET 4 there's a lot more support for higher-level abstractions (including lock-free code). Either way, I still wouldn't recommend using the synchronized wrappers.
There's a major problem with the Synchronized methods in the old collection library, in that they synchronize at too low a level of granularity (per method rather than per unit-of-work).
There's a classic race condition with a synchronized queue, shown below where you check the Count to see if it is safe to dequeue, but then the Dequeue method throws an exception indicating the queue is empty. This occurs because each individual operation is thread-safe, but the value of Count can change between when you query it and when you use the value.
object item;
if (queue.Count > 0)
{
// at this point another thread dequeues the last item, and then
// the next line will throw an InvalidOperationException...
item = queue.Dequeue();
}
You can safely write this using a manual lock around the entire unit-of-work (i.e. checking the count and dequeueing the item) as follows:
object item;
lock (queue)
{
if (queue.Count > 0)
{
item = queue.Dequeue();
}
}
So as you can't safely dequeue anything from a synchronized queue, I wouldn't bother with it and would just use manual locking.
.NET 4.0 should have a whole bunch of properly implemented thread-safe collections, but that's still nearly a year away unfortunately.
There's frequently a tension between demands for 'thread safe collections' and the requirement to perform multiple operations on the collection in an atomic fashion.
So Synchronized() gives you a collection which won't smash itself up if multiple threads add items to it simultaneously, but it doesn't magically give you a collection that knows that during an enumeration, nobody else must touch it.
As well as enumeration, common operations like "is this item already in the queue? No, then I'll add it" also require synchronisation which is wider than just the queue.
This way we don't need to lock the queue just to find out it was empty.
object item;
if (queue.Count > 0)
{
lock (queue)
{
if (queue.Count > 0)
{
item = queue.Dequeue();
}
}
}
It seems clear to me that using a lock(...) {...} lock is the right answer.
To guarantee the thread safety of the Queue, all operations must be done through this wrapper only.
If other threads access the queue without using .Synchronized(), then you'll be up a creek - unless all your queue access is locked up.