Multithreading and Locking (Thread-Safe operations) - c#

So I have a class with a few methods which all use locking in order to prevent weird things happening when someone uses an instance of my class with multiple threads accessing it:
public class SomeRandomClass
{
private object locker = new object();
public void MethodA()
{
lock (locker)
{
// Does something
MethodB();
}
}
public void MethodB()
{
lock (locker)
{
// Does something else
}
}
}
As we can see, MethodB() is automatically accessed by MethodA(), but that won't work since MethodA() has currently locked the locker object.
I want to make MethodB() accessible publicly, so you can call it manually whenever needed, but I do NOT want it to be used while MethodA() is doing things (that's why I'm using a locker object).
And of course I do not want MethodA() to do things while MethodB() is doing stuff. I basically want only one of all the methods to be used at the same time, but MethodA() needs to access MethodB() somehow without removing the lock (so that it stays completely thread-safe the whole time).
I really hope it is kind of understandable what I'm trying to ask... If there's any questions about my question, then please go ahead and post them below. Answers/Solutions are very much appreciated as well!
The solution is probably incredibly easy and I'm just not seeing it.
By the way, the above is supposed to be C#-code.

An easy solution would be to create a private method that contains what MethodB does that can be called by MethodA and another public MethodB
The private MethodB does not lock, only the public ones do.
For example:
public class SomeRandomClass {
private object locker = new object();
public void MethodA {
lock(locker) {
// exclusive club
// do something before calling _methodB
_methodB();
}
}
private void _methodB {
// do that, what used to be done by MethodB
}
public void MethodB {
//this one only exists to expose _methodB in a thread-safe context
lock(locker) {
_methodB();
}
}
}
P.S.
I think it is obvious to you and everyone else why your code is somewhat designed to create a deadlock.
Update:
Apparently lock(object) {} is re-entrant as pointed out in the comments, so the obvious deadlock isn't even one.

Locking forbids what you're trying to do -- that's its purpose.
One thing to do here is creating a private method that you can access from both methodA and methodB. That method wouldn't use locking, and wouldn't be thread safe, but could be called from either one of the locking methods.

You have race condition here: it make data incorrect. I suppose method A write static theVar variable of type string:
thread A -> call method A -> lock -> change theVar to "A"
thread B -> call method B -> wait because thread A keep lock
thread A -> release lock to call method B
The bug here: thread B process theVar of "A"
If method B only read theVar, it's Ok.

Your lock mechanism needs to allow locks to be taken in a recursive way (by the same thread only), usually called reentrant. lock (Monitor class internally).
It is legal for the same thread to invoke Enter more than once without it blocking; however, an equal number of Exit calls must be invoked before other threads waiting on the object will unblock.
See also Recursive / nested locking in C# with the lock statement
and Re-entrant locks in C#
As pointed out by Henk Holterman in the comment, the Monitor class is already reentrant. And the lock statement is managing the right amount of Enter and Exit calls to the underlying Monitor class.
The ReaderWriterLockSlim class is an example for a lock mechanism where one can choose between reentrant and non-reentrant. See https://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim(v=vs.110).aspx
var rwLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
Replace your lock { ... } with
ReaderWriterLockSlim rwLock =
new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
...
try
{
rwLock.EnterWriteLock();
// Does something
}
finally
{
rwLock.ExitWriteLock();
}
```

The Code written by you is correct.
Because according to Microsoft, once the call is acquired even if program calls for lock in the same flow, it will not be blocked as lock is already with the thread.
The code works as below.
call "MethodA" -->acquire lock --> call "MethodB" (will not be blocked as thread is already acquired lock) and execution will be completed.
Call "MethodB" in between previous execution from another thread, the execution will be blocked as lock is with first thread.

Related

Conditional thread lock in c#

Is it possible to have a conditional thread lock when the underlying condition is not constant?
I have two functions A and B, and a condition to decide which function to execute.
A is thread safe by itself, multiple calls to A can execute simultaneously, B is not, and is Synchronized. But during execution of B the condition can change (from false to true) and therefore all threads executing A at that time will throw errors.
if (condition)
{
A();
}
else
{
B();
}
A - thread safe
B - Synchronized using [MethodImpl(MethodImplOptions.Synchronized)]
Therefore, I am looking for a way to lock A but only when B is running.
Please suggest a way to achieve this.
Some elaborations:
I am creating a cache, and performance is very crucial, thus a blanket lock is not feasible.
Condition is whether or not the requested data is present in the cache.
A() = AddToUpdates() - Executed on a cache hit, just adds to the number of updates for a particular cache key, using a concurrent dictionary.
B() = ProccessUpdates() and EvictLeastPriorityEntry() - Executed on a cache miss, all previous updates will be processed and the underlying data structure storing the ordering of cache entries will be re-arranged.
And then the entry with least priority will be removed.
As mentioned in the accepted answer ReaderWriterLock seems to be the way to go.
Just one problem though,
Let's say, thread1 starts execution and a cache hit occurs, (on the entry with the least priority) meaning the if condition is true and enters the if block. But before calling A(), control is switched to thread2.
thread2 - cache miss occurs, reordering and eviction (Entry which A() from thread1 needed access to) is performed.
Now when controlled is returned to thread1, error will occur.
This is the solution I feel should work:
_lock.EnterReadLock();
if (condition)
{
A();
}
_lock.ExitReadLock();
if (!condition)
{
B();
}
void A()
{
// ....
}
void B()
{
_lock.EnterWriteLock();
// ...
_lock.ExitWriteLock();
}
Will this work?
Thank you.
I possible solution to your problem might be the ReaderWriterLockSlim class. This is a synchronization primitive that allows multiple concurrent readers, or one exclusive writer, but not both of those at the same time.
Use ReaderWriterLockSlim to protect a resource that is read by multiple threads and written to by one thread at a time. ReaderWriterLockSlim allows multiple threads to be in read mode, allows one thread to be in write mode with exclusive ownership of the lock, and allows one thread that has read access to be in upgradeable read mode, from which the thread can upgrade to write mode without having to relinquish its read access to the resource.
Example:
private readonly ReaderWriterLockSlim _lock = new();
void A()
{
_lock.EnterReadLock();
try
{
//...
}
finally { _lock.ExitReadLock(); }
}
void B()
{
_lock.EnterWriteLock();
try
{
//...
}
finally { _lock.ExitWriteLock(); }
}
Your question looks a lot like this:
A() is some read only method, so thread safe. Different execution of A in parallel is OK.
B() is like writing/mutating things that A method uses. So A() becomes not thread safe if executed at same time.
For example B() could write in a List and A() executions read on this list. And you would get exception "InvalidOperationException: Collection Was Modified" thrown from A() .
I advise you to look for "producer/consumer problem" in google and look for the tons of example there are.
But in case you absolutely want to begins B execution while A execution(s) has/have not terminated, you can add checkpoint in A() using Monitor class, it is used to lock a resource and synchronize with other threads. It is more complex though and i would go first for producer/consumer pattern to see if it fill the needs
Some more things:
I would check is the use of BlockingCollection<T> class that may fit your exact need too (and is easy to use)
The use of MethodImplOptions.Synchronized is not recommended because it use public lock. We use usually use private lock (object readonly _lock = new object();) so no one except the maintainer of this object can lock on it, thus preventing dead lock (and preventing other people accusing your code of a bug because other people locked your instance of class without knowing you do the same internally)

Locking two methods and ensure that only on thread is calling one method

In a class I've two methods:
Method1(): void
Method2(): void
This class can be accessed by multiple threads.
How can I realise, if "thread1" call "Method1", that "thread2" is waiting in "Method2" or in "Method1". This logic should also work, if "thread2" is calling "Method2", that "thread1" is waiting in "Method1" or "Method2"
My idea is this:
private object _lock = new object();
void Method1() {
lock(_lock){
//TODO: do something
}
}
void Method2() {
lock(_lock){
//TODO: do something
}
}
Will this work?
Your code will work after your clarification in comments.
With the given code you will:
Ensure only one thread can execute either Method1 or Method2 at the same time
If one thread is inside Method1, other threads will wait if they try to call either Method1 or Method2.
If Method1 calls into Method2 or vice versa, this will also work as the same thread can lock the same object more than once.
In other words, this is not a deadlock:
lock (x)
lock (x)
....
So your code should work just fine.
You cant do on same object, You can use Monitor. Monitor allows re-entrancy
You can use the WaitOne() function of an AutoResetEvent to allow only one function to access resources at a time, when it's finished called Set().
Example here: Synchronizing two threads with AutoResetEvent
MSDN Reference: https://msdn.microsoft.com/en-us/library/system.threading.autoresetevent(v=vs.110).aspx
Your methods should be Synchronized. See C# version of java's synchronized keyword? to get an idea on how to do it in c#.
This will work. Since you're locking on the same object, only one lock { } block will be executed at a given time.
How can I realise, if "thread1" call "Method1", that "thread2" is waiting in "Method2" or in "Method1". This logic should also work, if "thread2" is calling "Method2", that "thread1" is waiting in "Method1" or "Method2"
The logic will work. But not sure what you're trying to ask here.

Is it possible to create a deadlock in C# if nothing but the lock keyword is used around primitive data access?

I've written a lot of multi-threaded C# code, and I've never had a deadlock in any code I've released.
I use the following rules of thumb:
I tend to use nothing but the lock keyword (I also use other techniques such as reader/writer locks, but sparingly, and only if required for speed).
I use Interlocked.Increment if I am dealing with a long.
I tend to use the smallest granular unit of locking: I only tend to lock around primitive data structures such as long, dictionary or list.
I'm wondering if it's even possible to generate a deadlock if these rules are thumb are consistently followed, and if so, what the code would look like?
Update
I also use these rules of thumb:
Avoid adding a lock around anything that could pause indefinitely, especially I/O operations. If you absolutely have to do so, ensure that absolutely everything within the lock will time out after a set TimeSpan.
The objects I use for locking are always dedicated objects, e.g. object _lockDict = new object(); then lock(_lockDict) { // Access dictionary here }.
Update
Great answer from Jon Skeet. It also confirms why I never get deadlocks as I tend to instinctively avoid nested locks, and even if I do use them, I've always instinctively kept the entry order consistent.
And in response to my comment on tending to use nothing but the lock keyword, i.e. using Dictionary + lock instead of ConcurrentDictionary, Jon Skeet made this comment:
#Contango: That's exactly the approach I'd take too.
I'd go for simple code with locking over "clever" lock-free code every time, until there's evidence that it's causing an issue.
Yes, it's easy to deadlock, without actually accessing any data:
private readonly object lock1 = new object();
private readonly object lock2 = new object();
public void Method1()
{
lock(lock1)
{
Thread.Sleep(1000);
lock(lock2)
{
}
}
}
public void Method2()
{
lock(lock2)
{
Thread.Sleep(1000);
lock(lock1)
{
}
}
}
Call both Method1 and Method2 at roughly the same time, and boom - deadlock. Each thread will be waiting for the "inner" lock, which the other thread has acquired as its "outer" lock.
If you make sure you always acquire locks in the same order (e.g. "never acquire lock2 unless you already own lock1) and release the locks in the reverse order (which is implicit if you're acquiring/releasing with lock) then you won't get that sort of deadlock.
You can still get a deadlock with async code, with just a single thread involved - but that involves Task as well:
public async Task FooAsync()
{
BarAsync().Wait(); // Don't do this!
}
public async Task BarAsync()
{
await Task.Delay(1000);
}
If you run that code from a WinForms thread, you'll deadlock in a single thread - FooAsync will be blocking on the task returned by BarAsync, and the continuation for BarAsync won't be able to run because it's waiting to get back onto the UI thread. Basically, you shouldn't issue blocking calls from the UI thread...
As long as you ever only lock on one thing it's impossible, if one thread tries to lock on multiple locks, then yes. The dining philosophers problem nicely illustrates a simple deadlock caused with simple data.
As the other answers have already shown;
void Thread1Method()
{
lock (lock1)
{
// Do smth
lock (lock2)
{ }
}
}
void Thread2Method()
{
lock (lock2)
{
// Do smth
lock (lock2)
{ }
}
}
Addendum to what Skeet wrote:
The problem normally isn't with "only" two locks... (clearly there could be even with only two locks, but we want to play in Hard mode :-) )...
Let's say that in your program there are 10 lockable resources... Let's call them a1...a10. You must be sure that you'll always lock those in the same order, even for subsets of them... If a method needs a3, a5 and a7, and another methods needs a4, a5, a7, you must be sure that both will try locking them in the "right" order. For simplicity sake in this case the order is clear: a1->a10.
Normally lock objects aren't numbered, and/or they aren't taken in a single method... For example:
void MethodA()
{
lock (Lock1)
{
CommonMethod();
}
}
void MethodB()
{
lock (Lock3)
{
CommonMethod();
}
}
void CommonMethod()
{
lock (Lock2)
{
}
}
void MethodC()
{
lock (Lock1)
{
lock (Lock2)
{
lock (Lock3)
{
}
}
}
}
Here, even with the Lock* numbered, it isn't immediately clear that the locks could be taken in the wrong order (MethodB+CommonMethod take Lock3+Lock2, while MethodC takes Lock1+Lock2+Lock3)... It isn't immediately clear and we are playing with three very big advantages: we are speaking of deadlock, so we are looking for them, the locks are numbered and the whole code is around 30 lines.

Under what conditions can a thread enter a lock (Monitor) region more than once concurrently?

(question revised): So far, the answers all include a single thread re-entering the lock region linearly, through things like recursion, where you can trace the steps of a single thread entering the lock twice. But is it possible somehow, for a single thread (perhaps from the ThreadPool, perhaps as a result of timer events or async events or a thread going to sleep and being awaken/reused in some other chunk of code separately) to somehow be spawned in two different places independently of each other, and hence, run into the lock re-entrance problem when the developer didn't expect it by simply reading their own code?
In the ThreadPool Class Remarks (click here) the Remarks seem to suggest that sleeping threads should be reused when they're not in use, or otherwise wasted by sleeping.
But on the Monitor.Enter reference page (click here) they say "It is legal for the same thread to invoke Enter more than once without it blocking." So I figure there must be something I'm supposed to be careful to avoid. What is it? How is it even possible for a single thread to enter the same lock region twice?
Suppose you have some lock region that takes an unfortunately long time. This might be realistic, for example, if you access some memory that has been paged out (or whatever.) The thread in the locked region might go to sleep or something. Does the same thread become eligible to run more code, which might accidentally step into the same lock region? The following does NOT, in my testing, get multiple instances of the same thread to run into the same lock region.
So how does one produce the problem? What exactly do you need to be careful to avoid?
class myClass
{
private object myLockObject;
public myClass()
{
this.myLockObject = new object();
int[] myIntArray = new int[100]; // Just create a bunch of things so I may easily launch a bunch of Parallel things
Array.Clear(myIntArray, 0, myIntArray.Length); // Just create a bunch of things so I may easily launch a bunch of Parallel things
Parallel.ForEach<int>(myIntArray, i => MyParallelMethod());
}
private void MyParallelMethod()
{
lock (this.myLockObject)
{
Console.Error.WriteLine("ThreadId " + Thread.CurrentThread.ManagedThreadId.ToString() + " starting...");
Thread.Sleep(100);
Console.Error.WriteLine("ThreadId " + Thread.CurrentThread.ManagedThreadId.ToString() + " finished.");
}
}
}
Suppose you have a queue that contains actions:
public static Queue<Action> q = whatever;
Suppose Queue<T> has a method Dequeue that returns a bool indicating whether the queue could be successfully dequeued.
And suppose you have a loop:
static void Main()
{
q.Add(M);
q.Add(M);
Action action;
while(q.Dequeue(out action))
action();
}
static object lockObject = new object();
static void M()
{
Action action;
lock(lockObject)
{
if (q.Dequeue(out action))
action();
}
}
Clearly the main thread enters the lock in M twice; this code is re-entrant. That is, it enters itself, through an indirect recursion.
Does this code look implausible to you? It should not. This is how Windows works. Every window has a message queue, and when a message queue is "pumped", methods are called corresponding to those messages. When you click a button, a message goes in the message queue; when the queue is pumped, the click handler corresponding to that message gets invoked.
It is therefore extremely common, and extremely dangerous, to write Windows programs where a lock contains a call to a method which pumps a message loop. If you got into that lock as a result of handling a message in the first place, and if the message is in the queue twice, then the code will enter itself indirectly, and that can cause all manner of craziness.
The way to eliminate this is (1) never do anything even slightly complicated inside a lock, and (2) when you are handling a message, disable the handler until the message is handled.
Re-Entrance is possible if you have a structure like so:
Object lockObject = new Object();
void Foo(bool recurse)
{
lock(lockObject)
{
Console.WriteLine("In Lock");
if (recurse) { foo(false); }
}
}
While this is a pretty simplistic example, it's possible in many scenarios where you have interdependent or recursive behaviour.
For example:
ComponentA.Add(): locks a common 'ComponentA' object, adds new item to ComponentB.
ComponentB.OnNewItem(): new item triggers data-validation on each item in list.
ComponentA.ValidateItem(): locks a common 'ComponentA' object to validate the item.
Same-thread re-entry on the same lock is needed to ensure you don't get deadlocks occurring with your own code.
One of the more subtle ways you can recurse into a lock block is in GUI frameworks. For example, you can asynchronously invoke code on a single UI thread (a Form class)
private object locker = new Object();
public void Method(int a)
{
lock (locker)
{
this.BeginInvoke((MethodInvoker) (() => Method(a)));
}
}
Of course, this also puts in an infinite loop; you'd likely have a condition by which you'd want to recurse at which point you wouldn't have an infinite loop.
Using lock is not a good way to sleep/awaken threads. I would simply use existing frameworks like Task Parallel Library (TPL) to simply create abstract tasks (see Task) to creates and the underlying framework handles creating new threads and sleeping them when needed.
IMHO, Re-entering a lock is not something you need to take care to avoid (given many people's mental model of locking this is, at best, dangerous, see Edit below). The point of the documentation is to explain that a thread cannot block itself using Monitor.Enter. This is not always the case with all synchronization mechanisms, frameworks, and languages. Some have non-reentrant synchronization in which case you have to be careful that a thread doesn't block itself. What you do need to be careful about is always calling Monitor.Exit for every Monitor.Enter call. The lock keyword does this for you automatically.
A trivial example with re-entrance:
private object locker = new object();
public void Method()
{
lock(locker)
{
lock(locker) { Console.WriteLine("Re-entered the lock."); }
}
}
The thread has entered the lock on the same object twice so it must be released twice. Usually it is not so obvious and there are various methods calling each other that synchronize on the same object. The point is that you don't have to worry about a thread blocking itself.
That said you should generally try to minimize the amount the time you need to hold a lock. Acquiring a lock is not computationally expensive, contrary to what you may hear (it is on the order of a few nanoseconds). Lock contention is what is expensive.
Edit
Please read Eric's comments below for additional details, but the summary is that when you see a lock your interpretation of it should be that "all activations of this code block are associated with a single thread", and not, as it is commonly interpreted, "all activations of this code block execute as a single atomic unit".
For example:
public static void Main()
{
Method();
}
private static int i = 0;
private static object locker = new object();
public static void Method()
{
lock(locker)
{
int j = ++i;
if (i < 2)
{
Method();
}
if (i != j)
{
throw new Exception("Boom!");
}
}
}
Obviously, this program blows up. Without the lock, it is the same result. The danger is that the lock leads you into a false sense of security that nothing could modify state on you between initializing j and evaluating the if. The problem is that you (perhaps unintentionally) have Method recursing into itself and the lock won't stop that. As Eric points out in his answer, you might not realize the problem until one day someone queues up too many actions simultaneously.
ThreadPool threads cannot be reused elsewhere just because they went to sleep; they need to finish before they're reused. A thread that is taking a long time in a lock region does not become eligible to run more code at some other independent point of control. The only way to experience lock re-entry is by recursion or executing methods or delegates inside a lock that re-enter the lock.
Let's think about something other than recursion.
In some of business logics, they would like to control the behaviors of synchronization.
One of these patterns, they invoke Monitor.Enter somewhere and would like to invoke Monitor.Exit elsewhere later. Here is the code to get the idea about that:
public partial class Infinity: IEnumerable<int> {
IEnumerator IEnumerable.GetEnumerator() {
return this.GetEnumerator();
}
public IEnumerator<int> GetEnumerator() {
for(; ; )
yield return ~0;
}
public static readonly Infinity Enumerable=new Infinity();
}
public partial class YourClass {
void ReleaseLock() {
for(; lockCount-->0; Monitor.Exit(yourLockObject))
;
}
void GetLocked() {
Monitor.Enter(yourLockObject);
++lockCount;
}
void YourParallelMethod(int x) {
GetLocked();
Debug.Print("lockCount={0}", lockCount);
}
public static void PeformTest() {
new Thread(
() => {
var threadCurrent=Thread.CurrentThread;
Debug.Print("ThreadId {0} starting...", threadCurrent.ManagedThreadId);
var intanceOfYourClass=new YourClass();
// Parallel.ForEach(Infinity.Enumerable, intanceOfYourClass.YourParallelMethod);
foreach(var i in Enumerable.Range(0, 123))
intanceOfYourClass.YourParallelMethod(i);
intanceOfYourClass.ReleaseLock();
Monitor.Exit(intanceOfYourClass.yourLockObject); // here SynchronizationLockException thrown
Debug.Print("ThreadId {0} finished. ", threadCurrent.ManagedThreadId);
}
).Start();
}
object yourLockObject=new object();
int lockCount;
}
If you invoke YourClass.PeformTest(), and get a lockCount greater than 1, you've reentered; not necessarily be concurrent.
If it was not safe for reentrancy, you will get stuck in the foreach loop.
In the code block where Monitor.Exit(intanceOfYourClass.yourLockObject) will throw you a SynchronizationLockException, it is because we are trying to invoke Exit more than the times it have entered. If you are about to use the lock keyword, you possibly would not encounter this situation except directly or indirectly of recursive calls. I guess that's why the lock keyword was provided: it prevents the Monitor.Exit to be omitted in a careless manner.
I remarked the calling of Parallel.ForEach, if you are interested then you can test it for fun.
To test the code, .Net Framework 4.0 is the least requirement, and following additional name spaces are required, too:
using System.Threading.Tasks;
using System.Diagnostics;
using System.Threading;
using System.Collections;
Have fun.

Locking function body with function parameter object

Today I came across this piece of code
internal object UpdatePracownik(object employee)
{
lock (employee)
{
// rest of the code
}
return employee;
}
I was wondering if this is valid solution for locking access to function?
Wouldn't be better to use attribute
[MethodImpl(MethodImplOptions.Synchronized)]
instead of this kind of lock ?
Well it depends. If all threads call this method by passing the same globally visible object as parameter then they will all see the same lock and there will be no problems.
If instead each thread will call this method by passing its own object then locking is useless because they all see different locks. We must know the context in which the method is called to see if this is safe or not.
Using the synchronization method proposed by you makes the entire method body be wrapped in a lock(this) statement like:
internal object UpdatePracownik(object employee)
{
lock (this)
{
// code
}
}
which will guarantee atomicity of execution by multiple threads but may be too coarse-grain for your purposes and is generally not advisable.
Using the MethodImpl attribute to synchronise the method is equivalent to locking on an object that is specific to the method.
This means that only one thread at a time can run the method, but there might not be a need to exclude other threads as long as they don't use the same data.
It also means that the method is synchronised by itself, but you might want to lock other methods too using the same identifier. You might for example want the method DeletePracownik to be synchronised along with UpdatePracownik, so that you can't delete one object while it's being updated.
Locking on the employee instance is a bad idea, as is lock on 'this' both for the same reason: code outside of your control may also lock on those instances and cause deadlocks (blogs.msdn.com/b/bclteam/archive/2004/01/20/60719.aspx). It is preferable to use a private member:
private readonly object _lock = new object();
...
lock (_lock)
{
..
}
Furthermore you should familiarise yourself with ReaderWriterLockSlim. Often you may want to allow concurrent access to certain functions, unless a write operation is in progress:
private readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim();
public void ReadOp()
{
_rwLock.EnterReadLock(); //only blocks if write lock held
try
{
//do read op
}
finally
{
_rwLock.ExitReadLock();
}
}
public void WriteOp()
{
_rwLock.EnterWriteLock(); //blocks until no read or write locks held
try
{
//do write op
}
finally
{
_rwLock.ExitWriteLock();
}
}

Categories

Resources