Is ReaderWriterLockSlim.EnterReadLock necessary for List<SomeObject>.Count? - c#

Is someList.Count thread safe in C#?
Performance is very important to me and I can not use other thread safe collections due to the complexity of the main program
I know there can be many other cases, but just focus on this simple question:
Is _lock.EnterReadLock necessary for someList.Count or not because it might be an atomic attribute?
private ReaderWriterLockSlim _lock;
private List<SomeObject> _someList;
public void Add(SomeObject obj)
{
try
{
_lock.EnterReadLock();
if (_someList.Count < 10)
{
try
{
_lock.EnterWriteLock();
_someList.Add(obj);
}
finally
{
_lock.ExitWriteLock();
}
}
}
finally
{
_lock.ExitReadLock();
}
}

If you want to be guaranteed that any write operation has completed before you read the count a read lock is required. Assuming that write locks are used for all write actions.
To enter a write lock inside a read lock you have to use EnterUpgradeableReadLock . Calling EnterWriteLock when in a read lock will throw an exception. If you should use a write lock or upgradable lock please read https://stackoverflow.com/a/26578074/9271844.
For more information about the ReaderWriterLockSlim class refer to https://learn.microsoft.com/en-us/dotnet/api/system.threading.readerwriterlockslim?view=net-5.0

There will be no exception by not writing the _lock.EnterReadLock(), but the list.Count may not be expected number, so it is better to use the _lock.EnterReadLock() if we need the exact list.Count at the moment!

Related

System.Lazy<T> with different thread-safety mode [duplicate]

This question already has answers here:
Lazy<T> without exception caching
(7 answers)
Closed 19 days ago.
.NET 4.0's System.Lazy<T> class offers three Thread-Safety modes via the enum LazyThreadSafetyMode, which I'll summarise as:
LazyThreadSafetyMode.None - Not thread safe.
LazyThreadSafetyMode.ExecutionAndPublication - Only one concurrent thread will attempt to create the underlying value. On successful creation, all waiting threads will receive the same value. If an unhandled exception occurs during creation, it will be re-thrown on each waiting thread, cached and re-thrown on each subsequent attempt to access the underlying value.
LazyThreadSafetyMode.PublicationOnly - Multiple concurrent threads will attempt to create the underlying value but the first to succeed will determine the value passed to all threads. If an unhandled exception occurs during creation, it will not be cached and concurrent & subsequent attempts to access the underlying value will re-try the creation & may succeed.
I'd like to have a lazy-initialized value which follows slightly different thread-safety rules, namely:
Only one concurrent thread will attempt to create the underlying value. On successful creation, all waiting threads will receive the same value. If an unhandled exception occurs during creation, it will be re-thrown on each waiting thread, but it will not be cached and subsequent attempts to access the underlying value will re-try the creation & may succeed.
So the key differince with LazyThreadSafetyMode.ExecutionAndPublication is that if a "first go" at creation fails, it can be re-attempted at a later time.
Is there an existing (.NET 4.0) class that offers these semantics, or will I have to roll my own? If I roll my own is there a smart way to re-use the existing Lazy<T> within the implementation to avoid explicit locking/synchronization?
N.B. For a use case, imagine that "creation" is potentially expensive and prone to intermittent error, involving e.g. getting a large chunk of data from a remote server. I wouldn't want to make multiple concurrent attempts to get the data since they'll likely all fail or all succeed. However, if they fail, I'd like to be able to retry later on.
Only one concurrent thread will attempt to create the underlying
value. On successful creation, all waiting threads will receive the
same value. If an unhandled exception occurs during creation, it will
be re-thrown on each waiting thread, but it will not be cached and
subsequent attempts to access the underlying value will re-try the
creation & may succeed.
Since Lazy doesn't support that, you could try to roll it on your own:
private static object syncRoot = new object();
private static object value = null;
public static object Value
{
get
{
if (value == null)
{
lock (syncRoot)
{
if (value == null)
{
// Only one concurrent thread will attempt to create the underlying value.
// And if `GetTheValueFromSomewhere` throws an exception, then the value field
// will not be assigned to anything and later access
// to the Value property will retry. As far as the exception
// is concerned it will obviously be propagated
// to the consumer of the Value getter
value = GetTheValueFromSomewhere();
}
}
}
return value;
}
}
UPDATE:
In order to meet your requirement about same exception propagated to all waiting reader threads:
private static Lazy<object> lazy = new Lazy<object>(GetTheValueFromSomewhere);
public static object Value
{
get
{
try
{
return lazy.Value;
}
catch
{
// We recreate the lazy field so that subsequent readers
// don't just get a cached exception but rather attempt
// to call the GetTheValueFromSomewhere() expensive method
// in order to calculate the value again
lazy = new Lazy<object>(GetTheValueFromSomewhere);
// Re-throw the exception so that all blocked reader threads
// will get this exact same exception thrown.
throw;
}
}
}
Something like this might help:
using System;
using System.Threading;
namespace ADifferentLazy
{
/// <summary>
/// Basically the same as Lazy with LazyThreadSafetyMode of ExecutionAndPublication, BUT exceptions are not cached
/// </summary>
public class LazyWithNoExceptionCaching<T>
{
private Func<T> valueFactory;
private T value = default(T);
private readonly object lockObject = new object();
private bool initialized = false;
private static readonly Func<T> ALREADY_INVOKED_SENTINEL = () => default(T);
public LazyWithNoExceptionCaching(Func<T> valueFactory)
{
this.valueFactory = valueFactory;
}
public bool IsValueCreated
{
get { return initialized; }
}
public T Value
{
get
{
//Mimic LazyInitializer.EnsureInitialized()'s double-checked locking, whilst allowing control flow to clear valueFactory on successful initialisation
if (Volatile.Read(ref initialized))
return value;
lock (lockObject)
{
if (Volatile.Read(ref initialized))
return value;
value = valueFactory();
Volatile.Write(ref initialized, true);
}
valueFactory = ALREADY_INVOKED_SENTINEL;
return value;
}
}
}
}
Lazy does not support this. This is a design problem with Lazy because exception "caching" means that that lazy instance will not provide a real value forever. This can bring applications down permanently due to transient errors such as network problems. Human intervention is usually required then.
I bet this landmine exists in quite a few .NET apps...
You need to write your own lazy to do this. Or, open a CoreFx Github issue for this.
My attempt at a version of Darin's updated answer that doesn't have the race condition I pointed out... warning, I'm not completely sure this is finally completely free of race conditions.
private static int waiters = 0;
private static volatile Lazy<object> lazy = new Lazy<object>(GetValueFromSomewhere);
public static object Value
{
get
{
Lazy<object> currLazy = lazy;
if (currLazy.IsValueCreated)
return currLazy.Value;
Interlocked.Increment(ref waiters);
try
{
return lazy.Value;
// just leave "waiters" at whatever it is... no harm in it.
}
catch
{
if (Interlocked.Decrement(ref waiters) == 0)
lazy = new Lazy<object>(GetValueFromSomewhere);
throw;
}
}
}
Update: I thought I found a race condition after posting this. The behavior should actually be acceptable, as long as you're OK with a presumably rare case where some thread throws an exception it observed from a slow Lazy<T> after another thread has already returned from a successful fast Lazy<T> (future requests will all succeed).
waiters = 0
t1: comes in runs up to just before the Interlocked.Decrement (waiters = 1)
t2: comes in and runs up to just before the Interlocked.Increment (waiters = 1)
t1: does its Interlocked.Decrement and prepares to overwrite (waiters = 0)
t2: runs up to just before the Interlocked.Decrement (waiters = 1)
t1: overwrites lazy with a new one (call it lazy1) (waiters = 1)
t3: comes in and blocks on lazy1 (waiters = 2)
t2: does its Interlocked.Decrement (waiters = 1)
t3: gets and returns the value from lazy1 (waiters is now irrelevant)
t2: rethrows its exception
I can't come up with a sequence of events that will cause something worse than "this thread threw an exception after another thread yielded a successful result".
Update2: declared lazy as volatile to ensure that the guarded overwrite is seen by all readers immediately. Some people (myself included) see volatile and immediately think "well, that's probably being used incorrectly", and they're usually right. Here's why I used it here: in the sequence of events from the example above, t3 could still read the old lazy instead of lazy1 if it was positioned just before the read of lazy.Value the moment that t1 modified lazy to contain lazy1. volatile protects against that so that the next attempt can start immediately.
I've also reminded myself why I had this thing in the back of my head saying "low-lock concurrent programming is hard, just use a C# lock statement!!!" the entire time I was writing the original answer.
Update3: just changed some text in Update2 pointing out the actual circumstance that makes volatile necessary -- the Interlocked operations used here are apparently implemented full-fence on the important CPU architectures of today and not half-fence as I had originally just sort-of assumed, so volatile protects a much narrower section than I had originally thought.
Partially inspired by Darin's answer, but trying to get this "queue of waiting threads that are inflicted with the exception" and the "try again" features working:
private static Task<object> _fetcher = null;
private static object _value = null;
public static object Value
{
get
{
if (_value != null) return _value;
//We're "locking" then
var tcs = new TaskCompletionSource<object>();
var tsk = Interlocked.CompareExchange(ref _fetcher, tcs.Task, null);
if (tsk == null) //We won the race to set up the task
{
try
{
var result = new object(); //Whatever the real, expensive operation is
tcs.SetResult(result);
_value = result;
return result;
}
catch (Exception ex)
{
Interlocked.Exchange(ref _fetcher, null); //We failed. Let someone else try again in the future
tcs.SetException(ex);
throw;
}
}
tsk.Wait(); //Someone else is doing the work
return tsk.Result;
}
}
I am slightly concerned though - can anyone see any obvious races here where it will fail in an unobvious way?

Can a thread jump over lock()?

I have a class that provides thread-safe access to LinkedList<> (adding and reading items).
class LinkedListManager {
public static object locker = new object();
public static LinkedList<AddXmlNodeArgs> tasks { get; set; }
public static EventWaitHandle wh { get; set; }
public void AddItemThreadSafe(AddXmlNodeArgs task) {
lock (locker)
tasks.AddLast(task);
wh.Set();
}
public LinkedListNode<AddXmlNodeArgs> GetNextItemThreadSafe(LinkedListNode<AddXmlNodeArgs> prevItem) {
LinkedListNode<AddXmlNodeArgs> nextItem;
if (prevItem == null) {
lock (locker)
return tasks.First;
}
lock (locker) // *1
nextItem = prevItem.Next;
if (nextItem == null) { // *2
wh.WaitOne();
return prevItem.Next;
}
lock (locker)
return nextItem;
}
}
}
I have 3 threads: 1st - writes data to tasks; 2nd and 3rd - read data from tasks.
In 2nd and 3rd threads I retrieve data from tasks by calling GetNextItemThreadSafe().
The problem is that sometimes GetNextItemThreadSafe() returns null, when parameter of method (prevItem) is not null`.
Question:
Can a thread somehow jump over lock(locker) (// *1) and get to // *2 at once ??
I think it's the only way to get a return value = null from GetNextItemThreadSafe()...
I've spend a whole day to find the mistake, but it's extremely hard because it seems to be almost impossible to debug it step by step (tasks contains 5.000 elements and error occurs whenever it wants). Btw sometimes program works fine - without exception.
I'm new to threads so maybe I'm asking silly questions...
Not clear what you're trying to achieve. Are both threads supposed to get the same elements of the linked list ? Or are you trying to have 2 threads process the tasks out of the list in parallel ? If it's the second case, then what you are doing cannot work. You'd better look at BlockingCollection which is thread-safe and designed for this kind of multi-threaded producers/consumers patterns.
A lock is only active when executing the block of code declared following the lock. Since you lock multiple times on single commands, this effectively degenerates to only locking the single command that follows the lock, after which another thread is free to jump in and consume the data. Perhaps what you meant is this:
public LinkedListNode<AddXmlNodeArgs> GetNextItemThreadSafe(LinkedListNode<AddXmlNodeArgs> prevItem) {
LinkedListNode<AddXmlNodeArgs> nextItem;
LinkedListNode<AddXmlNodeArgs> returnItem;
lock(locker) { // Lock the entire method contents to make it atomic
if (prevItem == null) {
returnItem = tasks.First;
}
// *1
nextItem = prevItem.Next;
if (nextItem == null) { // *2
// wh.WaitOne(); // Waiting in a locked block is not a good idea
returnItem = prevItem.Next;
}
returnItem = nextItem;
}
return returnItem;
}
}
Note that only assignments (as opposed to returns) occur within the locked block and there is a single return point at the bottom of the method.
I think the solution is the following:
In your Add method, add the node and set the EventWaitHandle both inside the same lock
In the Get method, inside a lock, check if the next element is empty and inside the same lock, Reset the EventWaitHandle. Outside of the lock, wait on the EventWaitHandle.

Exceptions inside the lock block

Say, if I have the following block on C# code:
public class SynchedClass
{
public void addData(object v)
{
lock(lockObject)
{
//Shall I worry about catching an exception here?
//Do the work
//arr.Add(v);
}
}
private List<object> arr = new List<object>();
private object lockObject = new object();
}
Shall I attempt to catch exceptions inside the lock block? (My main concern is that the exception may be raised inside the lock which will prevent the lock from being "unlocked".)
Lock will be released when exception escapes from the lock block.
That is because lock(){...} is translate by compiler roughly into:
Monitor.Enter(obj);
try{
// contents of the lock block
}finally{
Monitor.Exit(obj);
}
There is more to consider than just releasing the mutex.
An exception occuring within a lock will release the lock, but what state is the program in now? A thread waiting on the lock will now wake up, and will perhaps now be dealing with invalid state. This is a difficult problem with no ideal solution.
The best thing is to try to keep your locks as small as possible and to call methods that don't throw. (That's ignoring the elephant in the room that is the evil ThreadAbortException...)
For a good discussion of these issues, see Eric Lippert's article: Locks and exceptions do not mix.
A lock statement of the form "lock (x) ..." where x is an expression of a reference-type, is precisely equivalent to (C# 4.0):
bool entered = false;
try {
System.Threading.Monitor.Enter(x, ref entered);
...
}
finally { if (entered) System.Threading.Monitor.Exit(x); }

Monitor vs lock

When is it appropriate to use either the Monitor class or the lock keyword for thread safety in C#?
EDIT:
It seems from the answers so far that lock is short hand for a series of calls to the Monitor class. What exactly is the lock call short-hand for? Or more explicitly,
class LockVsMonitor
{
private readonly object LockObject = new object();
public void DoThreadSafeSomethingWithLock(Action action)
{
lock (LockObject)
{
action.Invoke();
}
}
public void DoThreadSafeSomethingWithMonitor(Action action)
{
// What goes here ?
}
}
Update
Thank you all for your help : I have posted a another question as a follow up to some of the information you all provided. Since you seem to be well versed in this area, I have posted the link: What is wrong with this solution to locking and managing locked exceptions?
Eric Lippert talks about this in his blog:
Locks and exceptions do not mix
The equivalent code differs between C# 4.0 and earlier versions.
In C# 4.0 it is:
bool lockWasTaken = false;
var temp = obj;
try
{
Monitor.Enter(temp, ref lockWasTaken);
{ body }
}
finally
{
if (lockWasTaken) Monitor.Exit(temp);
}
It relies on Monitor.Enter atomically setting the flag when the lock is taken.
And earlier it was:
var temp = obj;
Monitor.Enter(temp);
try
{
body
}
finally
{
Monitor.Exit(temp);
}
This relies on no exception being thrown between Monitor.Enter and the try. I think in debug code this condition was violated because the compiler inserted a NOP between them and thus made thread abortion between those possible.
lock is just shortcut for Monitor.Enter with try + finally and Monitor.Exit. Use lock statement whenever it is enough - if you need something like TryEnter, you will have to use Monitor.
A lock statement is equivalent to:
Monitor.Enter(object);
try
{
// Your code here...
}
finally
{
Monitor.Exit(object);
}
However, keep in mind that Monitor can also Wait() and Pulse(), which are often useful in complex multithreading situations.
Update
However in C# 4 its implemented differently:
bool lockWasTaken = false;
var temp = obj;
try
{
Monitor.Enter(temp, ref lockWasTaken);
//your code
}
finally
{
if (lockWasTaken)
Monitor.Exit(temp);
}
Thanx to CodeInChaos for comments and links
Monitor is more flexible. My favorite use case of using monitor is:
When you don't want to wait for your turn and just skip:
//already executing? forget it, lets move on
if (Monitor.TryEnter(_lockObject))
{
try
{
//do stuff;
}
finally
{
Monitor.Exit(_lockObject);
}
}
As others have said, lock is "equivalent" to
Monitor.Enter(object);
try
{
// Your code here...
}
finally
{
Monitor.Exit(object);
}
But just out of curiosity, lock will preserve the first reference you pass to it and will not throw if you change it. I know it's not recommended to change the locked object and you don't want to do it.
But again, for the science, this works fine:
var lockObject = "";
var tasks = new List<Task>();
for (var i = 0; i < 10; i++)
tasks.Add(Task.Run(() =>
{
Thread.Sleep(250);
lock (lockObject)
{
lockObject += "x";
}
}));
Task.WaitAll(tasks.ToArray());
...And this does not:
var lockObject = "";
var tasks = new List<Task>();
for (var i = 0; i < 10; i++)
tasks.Add(Task.Run(() =>
{
Thread.Sleep(250);
Monitor.Enter(lockObject);
try
{
lockObject += "x";
}
finally
{
Monitor.Exit(lockObject);
}
}));
Task.WaitAll(tasks.ToArray());
Error:
An exception of type 'System.Threading.SynchronizationLockException'
occurred in 70783sTUDIES.exe but was not handled in user code
Additional information: Object synchronization method was called from
an unsynchronized block of code.
This is because Monitor.Exit(lockObject); will act on lockObject which has changed because strings are immutable, then you're calling it from an unsynchronized block of code.. but anyway. This is just a fun fact.
Both are the same thing. lock is c sharp keyword and use Monitor class.
http://msdn.microsoft.com/en-us/library/ms173179(v=vs.80).aspx
The lock and the basic behavior of the monitor (enter + exit) is more or less the same, but the monitor has more options that allows you more synchronization possibilities.
The lock is a shortcut, and it's the option for the basic usage.
If you need more control, the monitor is the better option. You can use the Wait, TryEnter and the Pulse, for advanced usages (like barriers, semaphores and so on).
Lock
Lock keyword ensures that one thread is executing a piece of code at one time.
lock(lockObject)
{
// Body
}
The lock keyword marks a statement block as a critical section by obtaining the mutual-exclusion lock for a given object, executing a statement and then releasing the lock
If another thread tries to enter a locked code, it will wait, block, until the object is released.
Monitor
The Monitor is a static class and belongs to the System.Threading namespace.
It provides exclusive lock on the object so that only one thread can enter into the critical section at any given point of time.
Difference between Monitor and lock in C#
The lock is the shortcut for Monitor.Enter with try and finally.
Lock handles try and finally block internally
Lock = Monitor + try finally.
If you want more control to implement advanced multithreading solutions using TryEnter() Wait(), Pulse(), and PulseAll() methods, then the Monitor class is your option.
C# Monitor.wait(): A thread wait for other threads to notify.
Monitor.pulse(): A thread notify to another thread.
Monitor.pulseAll(): A thread notifies all other threads within a process
In addition to all above explanations, lock is a C# statement whereas Monitor is a class of .NET located in System.Threading namespace.

C# Multithreading

Okay. I want to have two threads running. Current code:
public void foo()
{
lock(this)
{
while (stopThreads == false)
{
foreach (var acc in myList)
{
// process some stuff
}
}
}
}
public void bar()
{
lock(this)
{
while (stopThreads == false)
{
foreach (var acc in myList)
{
// process some stuff
}
}
}
}
Both are accessing the same List, the problem is that the first thread "foo" is not releasing the lock i guess; because "bar" only starts when "foo" is done. Thanks
Yes, that's how lock is designed to work.
The lock keyword marks a statement block as a critical section by obtaining the mutual-exclusion lock for a given object, executing a statement, and then releasing the lock.
Mutual-exclusion means that there can be at most one thread that holds the lock at any time.
Locking on this is a bad idea and is discouraged. You should create a private object and lock on that instead. To solve your problem you could lock on two different objects.
private object lockObject1 = new object();
private object lockObject2 = new object();
public void foo()
{
lock (lockObject1)
{
// ...
}
}
public void bar()
{
lock (lockObject2)
{
// ...
}
}
Alternatively you could reuse the same lock but move it inside the loop so that each loop has a chance to proceed:
while (stopThreads == false)
{
foreach (var acc in myList)
{
lock (lockObject)
{
// process some stuff
}
}
}
However I would suggest that you spend some time to understand what is going on rather than reordering the lines of code until it appears to work on your machine. Writing correct multithreaded code is difficult.
For stopping a thread I would recommend this article:
Shutting Down Worker Threads Gracefully
Since you are not really asking a question, I suggest you should read a tutorial on how threading works. A .Net specific guide can be found here. It features the topics "Getting Started", "Basic Synchronization", "Using Threads", "Advanced Threading" and "Parallel Programming".
Also, you are locking on "this". The Msdn says:
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 because
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.
The problem you have is that you work with a very coarse lock. Both Foo and Bad basically do not work concurrently because whoever starts first stops the other one for the COMPLETE WORK CYCLE.
It should, though, ONLY lock WHILE IT TAKES THINGS OUT OF THE LIST. Foreach does not work here - per definition. You ahve to put up a second list and have each thread REMOVE THE TOP ITEM (while lockin), then work on it.
Basically:
Foreach does not work, as both threads will run through the compelte list
Second, locks must be granular in that they only lock while needed.
In your case, you lock in foo will only be released when foo is finished.

Categories