c# why put object in the lock statement - c#

Can someone clarify me:
The statements inside the lock will be locked no one can go through unless it's finished and release the lock. then what is the object inside the lock used for
lock (obj)
{
///statement
}
Does that mean the obj is being locked and cannot be used from anywhere else unless the lock has done his work.

I've made a very simple class to illustrate what the object in the lock is there for.
public class Account
{
private decimal _balance = 0m;
private object _transactionLock = new object();
private object _saveLock = new object();
public void Deposit(decimal amount)
{
lock (_transactionLock)
{
_balance += amount;
}
}
public void Withdraw(decimal amount)
{
lock (_transactionLock)
{
_balance -= amount;
}
}
public void Save()
{
lock (_saveLock)
{
File.WriteAllText(#"C:\Balance.txt", _balance.ToString());
}
}
}
You'll notice that I have three locks, but only two variables.
The lines lock (_transactionLock) mutually lock the regions of code to only allow the current thread to enter - and this could mean that the current thread can re-enter the locked region. Other threads are blocked no matter which of the lock (_transactionLock) they hit if a thread already has the lock.
The second lock, lock (_saveLock), is there to show you that the object in the lock statement is there to identify the lock. So, if a thread were in one of the lock (_transactionLock) statements then there is nothing stopping a thread to enter the lock (_saveLock) block (unless another thread were already there).

Read up on semaphores and monitors. When it comes to multi-threading, you want to protect the Critical Section of the code, so that the object in question is not being accessed while an operation is being performed on it. The critical section is what's being enclosed inside the lock.
This is all done to avoid dead locks and live locks. Once again, you only need the lock if your application is multi-threaded.

Related

Why can threads change instance data if it is blocked in another thread?

I began to study lock and immediately a question arose.
It docs.microsoft says here:
The lock statement acquires the mutual-exclusion lock for a given
object, executes a statement block, and then releases the lock. While
a lock is held, the thread that holds the lock can again acquire and
release the lock. Any other thread is blocked from acquiring the lock
and waits until the lock is released.
I made a simple example proving that another thread with a method without the lock keyword can easily change the data of an instance while that instance is occupied by a method using the lock from the first thread. It is worth removing the comment from the blocking and the work is done as expected. I thought that a lock would block access to an instance from other threads, even if they don't use a lock on that instance in their methods.
Questions:
Do I understand correctly that locking an instance on one thread allows data from another thread to be modified on that instance, unless that other thread also uses that instance's lock? If so, what then does such a blocking generally give and why is it done this way?
What does this mean in simpler terms? While a lock is held, the thread that holds the lock can again acquire and release the lock.
So code formatting works well.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class A
{
public int a;
}
class Program
{
static void Main(string[] args)
{
A myA = new A();
void MyMethod1()
{
lock (myA)
{
for (int i = 0; i < 10; i++)
{
Thread.Sleep(500);
myA.a += 1;
Console.WriteLine($"Work MyMethod1 a = {myA.a}");
}
}
}
void MyMethod2()
{
//lock (myA)
{
for (int i = 0; i < 10; i++)
{
Thread.Sleep(500);
myA.a += 100;
Console.WriteLine($"Work MyMethod2 a = {myA.a}");
}
}
}
Task t1 = Task.Run(MyMethod1);
Thread.Sleep(100);
Task t2 = Task.Run(MyMethod2);
Task.WaitAll(t1, t2);
}
}
}
locks are cooperative, it relies on all parties that can change the data to cooperate and take the lock before attempting to change the data. Note that the lock does not care what you are changing inside the lock. It is fairly common to use a surrogate lock object when protecting some data structure. I.e.
private object myLockObject = new object();
private int a;
private int b;
public void TransferMonety(int amount){
lock(myLockObject){
if(a > amount){
a-=amount;
b+=amount;
}
}
}
Because of this locks are very flexible, you can protect any kind of operation, but you need to write your code correctly.
Because of this it is important to be careful when using locks. Locks should preferably be private to avoid any unrelated code from taking the lock. The code inside the lock should be fairly short, and should not call any code outside the class. This is done to avoid deadlocks, if arbitrary code is run it may do things like taking other locks or waiting for events.
While locks are very useful, there are also other synchronization primitives that can be used depending on your use case.
What does this mean in simpler terms? "While a lock is held, the thread that holds the lock can again acquire and release the lock."
It means that you can do this:
lock (locker)
{
lock (locker)
{
lock (locker)
{
// Do something while holding the lock
}
}
}
You can acquire the lock many times, and then release it an equal number of times. This is called reentrancy. The lock statement is reentrant, because the underlying Monitor class is reentrant by design. Other synchronization primitives, like the SemaphoreSlim, are not reentrant.

Monitor.Enter vs Monitor.Wait

I'm still unsure on the differences between these two calls. From MSDN,
Monitor.Enter(Object) Acquires an exclusive lock on the specified object.
Monitor.Wait(Object) Releases the lock on an object and blocks the current thread until it reacquires the lock.
From that I assume that Monitor.Wait is the same as Monitor.Enter except that it releases the lock on the object first before reacquiring.
Does the current thread have to have the lock in the first place? How could a different thread force a release on a lock of an object? Why would the same thread want to reacquire a lock?
According to MSDN: Monitor.Wait Method(Object)
SynchronizationLockException: The calling thread does not own the lock for the specified object.
In other words: You can only call Monitor.Wait(Object), when you already own the lock, whereas you call Monitor.Enter(Object) in order to acquire the lock.
As for why Monitor.Wait is needed: If your thread realizes, that it is lacking information to continue execution (e.g. it's waiting for a signal), you might want to let other threads enter the critical section, because not all threads have the same prerequisites.
For the waiting thread to continue execution, you will need to call Monitor.Pulse(Object) or Monitor.PulseAll(Object) before releasing the lock (otherwise, you're going to get the same kind of exception as with Monitor.Wait(Object)).
Keep in mind, that the next thread that acquires the lock after a pulse and after the lock was released, is not necessarily the thread that received the pulse.
Also keep in mind, that receiving a pulse, is not equivalent to having your condition met. You might still need to wait just a little longer:
// make sure to synchronize this correctly ;)
while (ConditionNotMet)
{
Monitor.Wait(mutex);
if (ConditionNotMet) // We woke up, but our condition is still not met
Monitor.Pulse(mutex); // Perhaps another waiting thread wants to wake up?
}
Consider this example:
public class EnterExitExample
{
private object myLock;
private bool running;
private void ThreadProc1()
{
while (running)
{
lock (myLock)
{
// Do stuff here...
}
Thread.Yield();
}
}
private void ThreadProc2()
{
while (running)
{
lock (myLock)
{
// Do other stuff here...
}
Thread.Yield();
}
}
}
Now you have two threads, each waiting for lock, then doing their stuff, then releasing the lock. The lock (myLock) syntax is just sugar for Monitor.Enter(myLock) and Monitor.Exit(myLock).
Let us now look at a more complicated example, where Wait and Pulse come into play.
public class PulseWaitExample
{
private Queue<object> queue;
private bool running;
private void ProducerThreadProc()
{
while (running)
{
object produced = ...; // Do production stuff here.
lock (queue)
{
queue.Enqueue(produced);
Monitor.Pulse(queue);
}
}
}
private void ConsumerThreadProc()
{
while (running)
{
object toBeConsumed;
lock (queue)
{
Monitor.Wait(queue);
toBeConsumed = queue.Dequeue();
}
// Do consuming stuff with toBeConsumed here.
}
}
}
What do we have here?
The producer produces an object whenever he feels like it. As soon as he has, he obtains lock on the queue, enqueues the object, then does a Pulse call.
At the same time, the consumer does NOT have lock, he left it by calling Wait. As soon as he gets a Pulse on that object, he will re-lock, and do his consuming stuff.
So what you have here is a direct thread-to-thread notification that there is something to do for the consumer. If you wouldn't have that, all you could do is have the consumer keep polling on the collection if there is something to do yet. Using Wait, you can make sure that there is.
As Cristi mentioned, a naive wait/pulse code does not work. Because your are completely missing the crucial point here : The monitor is NOT a message queue. If you pulse and no one is waiting, the pulse is LOST.
The right philosophy is that your are waiting for a condition, and if the condition is not satisfied, there is a way to wait for it, without eating cpu and without holding the lock. Here, the condition for the consumer is that there is something in the queue.
See https://ideone.com/tWqTS1 which work (a fork from by Cristi's example).
public class PulseWaitExample
{
private Queue<object> queue;
private bool running;
private void ProducerThreadProc()
{
while (running)
{
object produced = ...; // Do production stuff here.
lock (queue)
{
queue.Enqueue(produced);
Monitor.Pulse(queue);
}
}
}
private void ConsumerThreadProc()
{
while (running)
{
object toBeConsumed;
lock (queue)
{
// here is the fix
if (queue.Count == 0)
{
Monitor.Wait(queue);
}
toBeConsumed = queue.Dequeue();
}
// Do consuming stuff with toBeConsumed here.
}
}
}

Why doesn't Lock'ing on same object cause a deadlock? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Re-entrant locks in C#
If I write some code like this:
class Program {
static void Main(string[] args) {
Foo();
Console.ReadLine();
}
static void Foo() {
lock(_lock) {
Console.WriteLine("Foo");
Bar();
}
}
static void Bar() {
lock(_lock) {
Console.WriteLine("Bar");
}
}
private static readonly object _lock = new object();
}
I get as output:
Foo
Bar
I expected this to deadlock, because Foo acquires a lock, and then waits for Bar to acquire the lock. But this doesn't happen.
Does the locking mechanism simply allow this because the code is executed on the same thread?
For the same thread a lock is always reentrant, so the thread can lock an object as often as it wants.
Because you have only one thread here.
lock is shortcut for
bool lockWasTaken = false;
var temp = obj;
try {
Monitor.Enter(temp, ref lockWasTaken);
// your thread safe code
}
finally { if (lockWasTaken) Monitor.Exit(temp); }
Monitor.Enter acquire the Monitor on the object passed as the parameter. If another thread has executed an Enter on the object but has not yet executed the corresponding Exit, the current thread will block until the other thread releases the object. 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.
One word: Reentrant lock. If a thread has already acquired a lock, then it does not wait if it wants to acquire the lock again. This is very much needed otherwise it could have turned simple recursive functions into a nightmare.!
The lock statement is smarter than that, and it is designed to prevent just this. The lock is "owned" by the thread once it gets inside of it, so anytime it reaches another lock statement that locks on the same object it will realize that it already has access to that lock.

Confusion about the lock statement in C#

This is from MSDN:
The lock keyword ensures that one thread does not enter a critical section of code while another thread is in the critical section.
Does a critical section have to be same as the critical section?
Or does it mean:
The lock keyword ensures that one thread does not enter any critical section guarded by an object of code while another thread is in any critical section guarded by the same object. ?
class Program
{
static void Main(string[] args)
{
TestDifferentCriticalSections();
Console.ReadLine();
}
private static void TestDifferentCriticalSections()
{
Test lo = new Test();
Thread t1 = new Thread(() =>
{
lo.MethodA();
});
t1.Start();
Thread t2 = new Thread(() =>
{
lo.MethodB();
});
t2.Start();
}
}
public class Test
{
private object obj = new object();
public Test()
{ }
public void MethodA()
{
lock (obj)
{
for (int i = 0; i < 5; i++)
{
Thread.Sleep(500);
Console.WriteLine("A");
}
}
}
public void MethodB()
{
lock (obj)
{
for (int i = 0; i < 5; i++)
{
Thread.Sleep(500);
Console.WriteLine("B");
}
}
}
}
The question is confusingly worded and the answers so far are not particularly clear either. Let me rephrase the question into several questions:
(1) Does the lock statement ensure that no more than one thread is in the body of the lock statement at any one time?
No. For example:
static readonly object lock1 = new object();
static readonly object lock2 = new object();
static int counter = 0;
static object M()
{
int c = Interlocked.Increment(ref counter);
return c % 2 == 0 ? lock1 : lock2;
}
...
lock(M()) { Critical(); }
It is possible for two threads to both be in the body of the lock statement at the same time, because the lock statement locks on two different objects. Thread Alpha can call M() and get lock1, and then thread Beta can call M() and get lock2.
(2) Assuming that my lock statement always locks on the same object, does a lock statement ensure that no more than one "active" thread is in the body of the lock at any one time?
Yes. If you have:
static readonly object lock1 = new object();
...
lock(lock1) { Critical(); }
then thread Alpha can take the lock, and thread Beta will block until the lock is available before entering the lock body.
(3) Assuming that I have two lock statements, and both lock statements lock on the same object every time, does a lock statement ensure that no more than one "active" thread is in the body of either lock at any one time?
Yes. If you have:
static readonly object lock1 = new object();
...
static void X()
{
lock(lock1) { CriticalX(); }
}
static void Y()
{
lock(lock1) { CriticalY(); }
}
then if thread Alpha is in X and takes the lock, and thread Beta is in Y, then thread Beta will block until the lock is available before entering the lock body.
(4) Why are you putting "active" in "scare quotes"?
To call attention to the fact that it is possible for a waiting thread to be in the lock body. You can use the Monitor.Wait method to "pause" a thread that is in a lock body, and allow a blocked thread to become active and enter that lock body (or a different lock body that locks the same object). The waiting thread will stay in its "waiting" state until pulsed. At some time after it is pulsed, it rejoins the "ready" queue and blocks until there is no "active" thread in the lock. It then resumes at the point where it left off.
You put a lock on an object. If another thread tries to access a critical section marked by that object at the same time, it will block until the lock is removed/complete.
Example:
public static object DatabaseLck= new object();
lock (DatabaseLck) {
results = db.Query<T>(query).ToList();
}
Or
lock (DatabaseLck) {
results = db.Query<T>(string.Format(query, args)).ToList();
}
Neither one of those code blocks can be run at the same time BECAUSE they use the same lock object. If you used a different lock object for each, they could run at the same time.
It is one and the same critical section.
lock (synclock)
{
// the critical section protected by the lock statement
// Only one thread can access this at any one time
}
See lock Statement on MSDN:
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.
Or does it mean: The lock keyword ensures that one thread does not enter any critical section of code while another thread is in any critical section. ?
No. It does not mean that. It means the critical section protected by that lock and that lock alone.
Update, following code example:
If you use a single object to lock on, it will lock all critical sections, causing other threads to block until released. In your code example, once the lock in MethodA has been entered, all other threads reaching that lock and the lock on MethodB will block until the lock is released (this is happening because you are locking on the same object in both methods).
It does not mean any, though you can protect 2 blocks of code from being entered by more than one thread at the same time by locking them both with the same object. This is a common paradigm -- you may want to lock your collection for both clears and writes.
No it means that another thread wont enter THE critical section protected by this lock statement.
The Critical section is only defined by the programmer, and in this case, you could replace it by : the section protected by a lock
So translation :
The lock keyword ensures that one thread does not enter a section of code protected by a lock while another thread is in this section of code (protected by a lock )
The critical section that it is talking about is the section guarded by the lock statements.
Any critical section that is locking on the same object will be blocked from getting access.
It is also important that your lock object be static, because the locks need to be locking (or trying to lock) on the same instance of the lock object.

how to obtain a lock in two places but release on one place?

i'm newbie in c#. I need to obtain lock in 2 methods, but release in one method. Will that work?
public void obtainLock() {
Monitor.Enter(lockObj);
}
public void obtainReleaseLock() {
lock (lockObj) {
doStuff
}
}
Especially can I call obtainLock and then obtainReleaseLock? Is "doubleLock" allowed in C#? These two methods are always called from the same thread, however lockObj is used in another thread for synchronization.
upd: after all comments what do you think about such code? is it ideal?
public void obtainLock() {
if (needCallMonitorExit == false) {
Monitor.Enter(lockObj);
needCallMonitorExit = true;
}
// doStuff
}
public void obtainReleaseLock() {
try {
lock (lockObj) {
// doAnotherStuff
}
} finally {
if (needCallMonitorExit == true) {
needCallMonitorExit = false;
Monitor.Exit(lockObj);
}
}
}
Yes, locks are "re-entrant", so a call can "double-lock" (your phrase) the lockObj. however note that it needs to be released exactly as many times as it is taken; you will need to ensure that there is a corresponding "ReleaseLock" to match "ObtainLock".
I do, however, suggest it is easier to let the caller lock(...) on some property you expose, though:
public object SyncLock { get { return lockObj; } }
now the caller can (instead of obtainLock()):
lock(something.SyncLock) {
//...
}
much easier to get right. Because this is the same underlying lockObj that is used internally, this synchronizes against either usage, even if obtainReleaseLock (etc) is used inside code that locked against SyncLock.
With the context clearer (comments), it seems that maybe Wait and Pulse are the way to do this:
void SomeMethodThatMightNeedToWait() {
lock(lockObj) {
if(needSomethingSpecialToHappen) {
Monitor.Wait(lockObj);
// ^^^ this ***releases*** the lock (however many times needed), and
// enters the pending-queue; when *another* thread "pulses", it
// enters the ready-queue; when the lock is *available*, it
// reacquires the lock (back to as many times as it held it
// previously) and resumes work
}
// do some work, happy that something special happened, and
// we have the lock
}
}
void SomeMethodThatMightSignalSomethingSpecial() {
lock(lockObj) {
// do stuff
Monitor.PulseAll(lockObj);
// ^^^ this moves **all** items from the pending-queue to the ready-queue
// note there is also Pulse(...) which moves a *single* item
}
}
Note that when using Wait you might want to use the overload that accepts a timeout, to avoid waiting forever; note also it is quite common to have to loop and re-validate, for example:
lock(lockObj) {
while(needSomethingSpecialToHappen) {
Monitor.Wait(lockObj);
// at this point, we know we were pulsed, but maybe another waiting
// thread beat us to it! re-check the condition, and continue; this might
// also be a good place to check for some "abort" condition (and
// remember to do a PulseAll() when aborting)
}
// do some work, happy that something special happened, and we have the lock
}
You would have to use the Monitor for this functionality. Note that you open yourself up to deadlocks and race conditions if you aren't careful with your locks and having them taken and released in seperate areas of code can be risky
Monitor.Exit(lockObj);
Only one owner can hold the lock at a given time; it is exclusive. While the locking can be chained the more important component is making sure you obtain and release the proper number of times, avoiding difficult to diagnose threading issues.
When you wrap your code via lock { ... }, you are essentially calling Monitor.Enter and Monitor.Exit as scope is entered and departed.
When you explicitly call Monitor.Enter you are obtaining the lock and at that point you would need to call Monitor.Exit to release the lock.
This doesn't work.
The code
lock(lockObj)
{
// do stuff
}
is translated to something like
Monitor.Enter(lockObj)
try
{
// do stuff
}
finally
{
Monitor.Exit(lockObj)
}
That means that your code enters the lock twice but releases it only once. According to the documentation, the lock is only really released by the thread if Exit was called as often as Enter which is not the case in your code.
Summary: Your code will not deadlock on the call to obtainReleaseLock, but the lock on lockObj will never be released by the thread. You would need to have an explicit call to Monitor.Exit(lockObj), so the calls to Monitor.Enter matches the number of calls to Monitor.Exit.

Categories