ConcurrentDictionary enumeration and locking - c#

If I have a ConcurrentDictionary, do I need to lock it when looping thru it using foreach?

If I have a ConcurrentDictionary, do I need to lock it when looping thru it using foreach?
No. From the docs for ConcurrentDictionary.GetEnumerator:
The enumerator returned from the dictionary is safe to use concurrently with reads and writes to the dictionary, however it does not represent a moment-in-time snapshot of the dictionary. The contents exposed through the enumerator may contain modifications made to the dictionary after GetEnumerator was called.
As long as you're okay with that, you don't need any kind of locking.

Related

Creating a ConcurrentDictionary<string, ConcurrentQueue<decimal>> and keeping a specified ordering [duplicate]

I am using a ConcurrentDictionary to store log-lines, and when I need to display them to the user I call ToList() to generate a list. But the weird thing is that some users receive the most recent lines first in the list, while they should logically be last.
Is this because ConcurrentDictionary doesnt guarantee a persistent order on the IEnumerate interface, or what can be the reason?
No ConcurrentDictionary (and Dictionary<T> for that matter) does not guarantee the ordering of the keys in the list. You'll have to use a different data type or perform the sorting yourself. For non-concurrent code you would use SortedDictionary<T>, but I don't believe there is an analogue in the concurrent collections.
No. The list order of ConcurrentDictionary is NOT guaranteed, lines can come out in any order.

iterating through ConcurrentDictionary and modifying the collection

What is the correct way to iterate through ConcurrentDictionary collection and deleting some entries.
As I understand ConcurrentDictionary implements locking on a level of a cell, and for me is important to iterate through whole collection and remove irrelevant data via some condition. I affraid that through my iteration other thread will add data that should be filtered after my iterator was after that point in the collection.
So how I can achieve this with ConcurrentDictionary ,or should use ordinary Dictionary with locking mechanism on each touch of that collection.
Thanks.
ConcurrentDictionary's main advantage IMO is that it's lock free for the reading threads, which is usually why you'd use it; if you don't need that advantage then you can just use a dictionary with a lock.
You could always ensure the filter criteria are passed to any adds that occur after your filter iteration starts.
Otherwise, if non-blocking reads are more important than the occasional inconsistent entry, you could just repeat your filter until it finds no more invalid items.
Definetely you can't garante, that no entries will be added to ConcurrentDictionary while you iterate it without locking the dictionary. But if do locking, then there no sence in using ConcurrentDictionary, use Dictionary instead.
Btw, why it is important for you to end iteration with no 'bad' entries left? It can be populated with any of them the next moment after releasing the lock. Maybe it's better to not let unwanted entries to appear in dictionary?

is enumerator thread safe after getting with lock?

I am wondering if the returned enumerator is thread safe:
public IEnumerator<T> GetEnumerator()
{
lock (_sync) {
return _list.GetEnumerator();
}
}
If I have multiple threads whom are adding data (also within lock() blocks) to this list and one thread enumerating the contents of this list. When the enumerating thread is done it clears the list. Will it then be safe to use the enumerator gotten from this method.
I.e. does the enumerator point to a copy of the list at the instance it was asked for or does it always point back to the list itself, which may or may not be manipulated by another thread during its enumeration?
If the enumerator is not thread safe, then the only other course of action I can see is to create a copy of the list and return that. This is however not ideal as it will generate lots of garbage (this method is called about 60 times per second).
No, not at all. This lock synchronizes only access to _list.GetEnumerator method; where as enumerating a list is lot more than that. It includes reading the IEnumerator.Current property, calling IEnumerator.MoveNext etc.
You either need a lock over the foreach(I assume you enumerate via foreach), or you need to make a copy of list.
Better option is to take a look at Threadsafe collections provided out of the box.
According to the documentation, to guarantee thread-safity you have to lock collecton during entire iteration over it.
The enumerator does not have exclusive access to the collection;
therefore, enumerating through a collection is intrinsically not a
thread-safe procedure. To guarantee thread safety during enumeration,
you can lock the collection during the entire enumeration. To allow
the collection to be accessed by multiple threads for reading and
writing, you must implement your own synchronization.
Another option, may be define you own custom iterator, and for every thread create a new instance of it. So every thread will have it's own copy of Current read-only pointer to the same collection.
If I have multiple threads whom are adding data (also within lock() blocks) to this list and one thread enumerating the contents of this
list. When the enumerating thread is done it clears the list. Will it
then be safe to use the enumerator gotten from this method.
No. See reference here: http://msdn.microsoft.com/en-us/library/system.collections.ienumerator.aspx
An enumerator remains valid as long as the collection remains
unchanged. If changes are made to the collection, such as adding,
modifying, or deleting elements, the enumerator is irrecoverably
invalidated and the next call to MoveNext or Reset throws an
InvalidOperationException. If the collection is modified between
MoveNext and Current, Current returns the element that it is set to,
even if the enumerator is already invalidated. The enumerator does not
have exclusive access to the collection; therefore, 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.
..
does the enumerator point to a copy of the list at the instance it was asked for or does it always point back to the list itself, which
may or may not be manipulated by another thread during its
enumeration?
Depends on the collection. See the Concurrent Collections. Concurrent Stack, ConcurrentQueue, ConcurrentBag all take snapshots of the collection when GetEnumerator() is called and returns elements from the snapshot. The underlying collection may change without changing the snapshot. On the other hand, ConcurrentDictionary doesn't take a snapshot, so changing the collection while iterating will immediately effect things per the rules above.
A trick I sometimes use in this case is to create a temporary collection to iterate so the original is free while I use the snapshot:
foreach(var item in items.ToList()) {
//
}
If your list is too large and this causes GC churn, then locking is probably your best bet. If locking is too heavy, maybe consider a partial iteration each timeslice, if that is feasible.
You said:
When the enumerating thread is done it clears the list.
Nothing says you have to process the whole list at a time. You could instead remove a range of items, move them to a separate enumerating thread, let that process, and repeat. Perhaps iteratation and lists aren't the best model here. Consider the ConcurrentQueue with which you could build producers and consumer model, and consumers just steadily remove items to process without iteration

How should I keep 2 ConcurrentDictionaries in sync?

I like the lock-free operation of the ConcurrentDictionary and use it in two objects:
ConcurrentDictionary<datetime,myObj> myIndexByDate
ConcurrentDictionary<myObjSummary, ConcurrentDictionary<int, myObj> myObjectSummary Index
These two objects need to stay in Sync. Is the only way to do this is to use a Lock, thus avoiding all benefits of the Concurrent dictionary?
I would create a custom class with 2 dictionaries and use a lock only on the methods which are susceptible to change the dictionary(Add, Delete).
You don't lose the benefits of the concurrent dictionary as this method require much less code than what you would have to do using normal dictionary.
ConcurrentDictionary is only "thread-safe" on the operations on a particular instance. e.g. while a ConcurrentDictionary.TryAdd() call is being invoked, no other threads can be modifying the collection...
This doesn't mean that while you get an value from one dictionary and add it to another dictionary that the value still exists in the original dictionary while you're adding it to the second.
You probably have an invariant that details that while you're moving one value from one dictionary to the other, no values in the original dictionary can be removed (or at least that value, but that's a little more difficult to guarantee with ConncurrentDictionary.

C# - Locking a resource when obtained from dictionary

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.

Categories

Resources