The lock keyword is used where you want to achieve that the area should be executed by at most on thread, in a multithreading environment, rest of the thread will wait for the area.
I have a collection IList<Student> student=new List<Student>() that is being used in multiple classes.
In some places objects are getting added to the list, and in some places objects are getting deleted. This causes some inconsistent behavior.
Is it true that when I lock the collection in class x in a multithreading environment, the collection will be locked for all classes and all threads in different classes will wait for the lock?
Class StaticClass
{
Public static IList<Student> student=new List<Student>();
}
Class ClassA
{
//add an item in the collection
}
Class ClassB
{
//delete an item in the collection
}
Class ClassC
{
//lock the collection here
lock (StaticClass.student)
{
foreach (ConnectionManager con in ConnectionManager.GetAllStudents())
{
con.Send(offlinePresence);
}
}
}
When I have locked the collection in ClassC, will other threads for classA and ClassB wait? Until the for loop execute nobody is allowed to add or delete items in the collection, because the collection has been locked?
Take a look at System.Collections.Generic.SynchronizedCollection<T> from the System.ServiceModel.dll assembly. All of the locking stuff is built in.
As Fabio said, ConcurrentBag also works, but a separate list context is created for each thread accessing it. When you try and remove items, it works like a queue. Once you've run out of items in your own thread's list, it will then "steal" items from other threads' lists (in a thread-safe way).
For your task, I'm guessing the SynchronizedCollection would be better.
When your code acquires a lock on an object, it does not block access to that object from other threads. The only thing that happens to this object is that other threads cannot acquire a lock to the same object as long as the lock is not released.
It is common practice to reserve a separate plain object as the target of a lock.
In your example other threads can still access the List<Student> object as long as code does not explicitly lock it first.
Locking can cause serious performance issues (threads waiting for eachother) and in many cases does not need to be implemented explicitly. Just take a look at the Concurrent collection classes of the .NET Framework.
Related
To my understanding, they do not. Please confirm.
Suppose I have a Processor object that contains a List<T> where T is a reference type.
The UI thread instantiates the Processor object, and periodically calls into it to get the List<T>.
The processor object also starts a task that has a reference to the List<T> when it is constructed.
A lock is used to reserve access to the List<T> in the getter and in the task to ensure they have exclusive access to the List<T>.
public class Processor
{
private List<T> _list = new List<T>();
private Object _listLock = new Object();
public Processor()
{
// populate _list
Task t = new Task(Process);
t.Start();
}
public List<T> GetList()
{
lock(_listLock)
{
return _list;
}
}
private void Process()
{
while(!doneProcessing)
{
lock(_listLock)
{
// access and modify _list items
}
Thread.Sleep(...);
}
}
}
But even if List<T> is locked in the getter, and it returned the list reference without issue, the task started by the Processor is still modifying the reference type list elements when it seizes the lock.
The elements of the list are still subject to change from the Processor’s task, and accessing them in the UI thread would not be thread safe.
If I am correct, an obvious solution is to have the getter return a new list populated with deep copies of the list elements.
public List<T> GetList()
{
lock(_listLock)
{
return _list.Select(t => t.Clone()).ToList();
}
}
What else can you do?
Locks, used the way you have, will not ensure thread safety.
If you're trying for thread safety, consider using one of the thread safe collections available in the .NET CLR.
You'll notice there is no thread-safe IList. Here's why. The very notion of a thread safe list doesn't make a lot of sense. But with some minor design changes you could easily use something like a ConcurrentDictionary or ConcurrentBag.
Your GetList() doesn't do what you think it does:
public List<T> GetList()
{
lock(_listLock)
{
return _list;
}
}
Since GetList() just returns a reference to _list, the lock() does nothing except prevent 2 threads from getting a reference to _list at the same time, which is not an issue anyway.
The issue is that you are passing a reference to a list object back to the UI thread, and the elements in the list pointed to by the reference could change at any time, event while the UI thread is iterating over the elements, which is not good.
You could expose the lock object to the UI thread, but this means your UI will need to block while the list is being updated, which is usually undesirable (blocking UI thread degrades user experience).
Depending on what your UI does with the list, it might be better to take an immutable snapshot of your list and return that to the UI.
If you are wanting to keep the UI in step with changes to the underlying list data, then the approach you take really depends on the UI technology.
Assuming I have an object A containing
// ...
private List<double> someList = new List<double>();
// ...
public List<double> SomeList
{
get { lock (this) { return someList; } }
}
// ...
would it be thread safe to perform operation on the list as in the code below. Knowing that several operations could be executed simultaneously by different threads.
A.SomeList.Add(2.0);
or
A.SomeList.RemoveAt(0);
In other words, when is the lock released?
There is no thread safety here.
The lock is released as soon as the block it protects is finished, just before the property returns, so the calls to Add ad RemoveAt are not protected by the lock.
The lock you shown in the question isn't of much use.
To make list operations thread safe you need to implement your own Add/Remove/etc methods wrapping those of the list.
public void Add(double item)
{
lock(_list)
{
_list.Add(item);
}
}
Also, it's a good idea to hide the list itself from the consumers of your class, i.e. make the field private.
The lock is released when you exit the body of the lock statement. That means that your code is not thread-safe.
In other words, you can be sure that two threads won't be executing return someList on the same object at the same time. But it's certainly possible that one thread will execute Add() at the same time as another thread will execute RemoveAt(), which is what makes it non thread-safe.
The lock is released when the code inside the lock is finished executing.
Also, locking on this will only affect the current instance of the object
Ok, just for the hell of it.
There IS a way to make your object threadsafe, by using architectures that are already threadsafe.
For example, you could make your object a single threaded COM object. The COM object will be thread safe, but you'll pay with performance (the price of being lazy and not managing your own locks).
Create a COM Object in C#
...others said already, but just to formalize a problem a bit...
First, lock (this) {...} suggests a 'scope' - e.g. like using (){} - it only locks (this in this case) for variables inside. And that's a 'good thing' :) actually, as if you couldn't rely on that the whole locks/synchronization concept would be very much useless,
lock (this) { return something; } is an oxymoron of a sort - it's returning something that unlocks the very same moment it returns,
And the problems I think is the understanding of how it works. 'lock()' is not 'persisted' in a state of the object, so that you could return it etc. Take a look here how it's implemented How does lock work exactly? - answer explains it. It's more of a 'critical section' - i.e. you protect certain parts of 'code', which uses the variable - not the variable itself. Any type of synchronization requires 'synchronization objects' to hold the locks - and to be disposed of once lock is no longer needed. Take a look at this post https://stackoverflow.com/a/251668/417747, Esteban formulated that very well,
"Finally, there is the common misconception that lock(this) actually modifies the object passed as a parameter, and in some way makes it read-only or inaccessible. This is false. The object passed as a parameter to lock merely serves as a key" (this is a quote)
you either (usually) lock 'private code' of a class method, property... - to synchronize access to something you're doing inside - and access being to a private member (again usually) so that nobody else can access it w/o going through your synchronized code.
Or you make a thread-safe 'structure' - like a list - which is already 'synchronized' inside so that you can access it in a thread-safe manner. But there are no such things (or not used, almost never) as passing locks around or having one place lock the variable, while the other part of the code unlocks it etc. (in that case it's some type of EventWaitHandle that's rather used to synchronize things in between 'distant' code where one fires off on another etc.)
In your case, the choice is I think to go with the 'synchronized structure', i.e. the list that's internally handled,
In my app I have a List of objects. I'm going to have a process (thread) running every few minutes that will update the values in this list. I'll have other processes (other threads) that will just read this data, and they may attempt to do so at the same time.
When the list is being updated, I don't want any other process to be able to read the data. However, I don't want the read-only processes to block each other when no updating is occurring. Finally, if a process is reading the data, the process that updates the data must wait until the process reading the data is finished.
What sort of locking should I implement to achieve this?
This is what you are looking for.
ReaderWriterLockSlim is a class that will handle scenario that you have asked for.
You have 2 pair of functions at your disposal:
EnterWriteLock and ExitWriteLock
EnterReadLock and ExitReadLock
The first one will wait, till all other locks are off, both read and write, so it will give you access like lock() would do.
The second one is compatible with each other, you can have multiple read locks at any given time.
Because there's no syntactic sugar like with lock() statement, make sure you will never forget to Exit lock, because of Exception or anything else. So use it in form like this:
try
{
lock.EnterWriteLock(); //ReadLock
//Your code here, which can possibly throw an exception.
}
finally
{
lock.ExitWriteLock(); //ReadLock
}
You don't make it clear whether the updates to the list will involve modification of existing objects, or adding/removing new ones - the answers in each case are different.
To handling modification of existing items in the list, each object should handle it's own locking.
To allow modification of the list while others are iterating it, don't allow people direct access to the list - force them to work with a read/only copy of the list, like this:
public class Example()
{
public IEnumerable<X> GetReadOnlySnapshot()
{
lock (padLock)
{
return new ReadOnlyCollection<X>( MasterList );
}
}
private object padLock = new object();
}
Using a ReadOnlyCollection<X> to wrap the master list ensures that readers can iterate through a list of fixed content, without blocking modifications made by writers.
You could use ReaderWriterLockSlim. It would satisfy your requirements precisely. However, it is likely to be slower than just using a plain old lock. The reason is because RWLS is ~2x slower than lock and accessing a List would be so fast that it would not be enough to overcome the additional overhead of the RWLS. Test both ways, but it is likely ReaderWriterLockSlim will be slower in your case. Reader writer locks do better in scenarios were the number readers significantly outnumbers the writers and when the guarded operations are long and drawn out.
However, let me present another options for you. One common pattern for dealing with this type of problem is to use two separate lists. One will serve as the official copy which can accept updates and the other will serve as the read-only copy. After you update the official copy you must clone it and swap out the reference for the read-only copy. This is elegant in that the readers require no blocking whatsoever. The reason why readers do not require any blocking type of synchronization is because we are treating the read-only copy as if it were immutable. Here is how it can be done.
public class Example
{
private readonly List<object> m_Official;
private volatile List<object> m_Readonly;
public Example()
{
m_Official = new List<object>();
m_Readonly = m_Official;
}
public void Update()
{
lock (m_Official)
{
// Modify the official copy here.
m_Official.Add(...);
m_Official.Remove(...);
// Now clone the official copy.
var clone = new List<object>(m_Official);
// And finally swap out the read-only copy reference.
m_Readonly = clone;
}
}
public object Read(int index)
{
// It is safe to access the read-only copy here because it is immutable.
// m_Readonly must be marked as volatile for this to work correctly.
return m_Readonly[index];
}
}
The code above would not satisfy your requirements precisely because readers never block...ever. Which means they will still be taking place while writers are updating the official list. But, in a lot of scenarios this winds up being acceptable.
If I have multiple threads calling the Add method of a List object, and no readers, do I only need to lock on the List object before calling Add to be thread safe?
Usually it's best to lock on a separate (immutable) object... locking on the same object you're modifying is bad practice should be done with caution.
private readonly object sync = new object();
private List<object> list = new List<object>();
void MultiThreadedMethod(object val)
{
lock(sync)
{
list.Add(val);
}
}
In a basic case like this you will not have a problem, but if there is a possibility that your list can be changed (not the contents of the list, but the list itself), then you might have a situation where you lock on two objects when you only intend to lock on one.
Yes. But you might also consider subclassing the List and "new" over the Add method. That will allow you to encapsulate the lock. It will work great as long as nothing accesses the base List. This technique is used for simple tree structures in XNA video games.
Yes, you need to lock. Instance methods are not guaranteed to be thread safe on List<T>.
I think these have been linked before on here, but I found them to be very useful and interesting:
Thread safe collections are hard
Thread safe collection
I have a static collections which implements IList interface. This collection is used throughout the application, including adding/removing items.
Due to multithread issue, I wonder what I can do to ensure that the list is modifying one at a time, such as when 1 thread try to add an item, another thread should not do delete item at that time.
I wonder what is difference between lock(this) and lock(privateObject) ? Which one is better in my case?
Thank you.
The lock(this) will lock on the entire instance while lock(privateObject) will only lock that specific instance variable. The second one is the better choice since locking on the entire instance will prevent other threads from being able to do anything with the object.
From MSDN:
In general, avoid locking on a public
type, or instances beyond your code's
control. The common constructs lock
(this), lock (typeof (MyType)), and
lock ("myLock") violate this
guideline:
lock (this) is a problem if the
instance can be accessed publicly.
lock (typeof (MyType)) is a problem if
MyType is publicly accessible.
lock(“myLock”) is a problem since any
other code in the process using the
same string, will share the same lock.
Best practice is to define a private
object to lock on, or a private static
object variable to protect data common
to all instances.
In this particular case, the collection is static which effectively means there is a single instance but that still doesn't change how the lock(this) and lock(privateObject) would behave.
By using lock(this) even in a static collection you are still locking the entire instance. In this case, as soon as thread A acquires a lock for method Foo() all other threads will have to wait to perform any operation on the collection.
Using lock(privateObject) means that as soon as thread A acquires a lock for method Foo() all other threads can perform any other operation except Foo() without waiting. Only when another thread tries to perform method Foo() will it have to wait until thread A has completed its Foo() operation and released the lock.
The lock keyword is a little confusing. The object expression in the lock statement is really just an identification mechanism for creating critical sections. It is not the subject of the lock nor is it in any way guarenteed to be safe for multithreaded operations just because it is referenced by the statement.
So lock(this) is creating a critical section identified by the class containing the currently executing method whereas lock(privateObject) is identified by an object that is (presumably anyway) private to the class. The former is more risky because a caller of your class could inadvertantly define their own critical sections using a lock statement that uses that class instance as the lock object. That could lead to unintended threading problems including, but not limited to, deadlocks and bottlenecks.
You mentioned that you were concerned with multiple threads modifying the collection at the same time. I should point out that you should be equally concerned with threads reading the collection as well even if they are not modifying it. It is likely that you will need some of the same safe guards in place to protect the collection during reads as you would during writes.
Add a private member to the class that methods lock on.
eg.
public class MyClass : IList
{
private object syncRoot = new object();
public void Add(object value)
{
lock(this.syncRoot)
{
// Add code here
}
}
public void Remove(object value)
{
lock(this.syncRoot)
{
// Remove code here
}
}
}
This will ensure that access to the list is syncronized between threads for the adding and removing cases, while maintaining access to the list. This will still let enumerators access the list while another thread can modify it, but that then opens another issue where an enumerator will throw an exception if the collection is modified during the enumeration.