How to use Monitor in threading without exclusive lock? - c#

I have a C#/.Net application.
I use Monitor.Enter and Monitor.Exit to acquire exclusive access on some object to synchronize threads.
I have a specific case where a thread 1 should acquire exclusive access on some object. Another thread 2 should behave as follows : I there is no exclusive lock on the object, it should continue without acquiring exclusive lock. I there is already an exclusive lock acquired by another thread, It should wait until it's released.
I have been looking in the documentation here.
But I couldn't find any function that does this.
Is that possible please?

So:
if the object is currently locked, you wish to wait for it to be released, but not take the lock
if the object is not currently locked, you wish to continue without holding the lock
I believe that is achieved by simply:
lock (theThing) {}
This acquires and releases, which has the same semantics as not taking the lock, but waiting for anyone who does hold it.
Note that there is inherently a race condition in what you ask, as if you're not taking the lock: someone else could after you've checked. We long as that is OK.
There are also a myriad of methods on Monitor for other scenarios, usually mixed with try/finally - in particular, TryEnter with a zero timeout can be used for "take the lock immediately if you can, but don't wait if you can't".
However, a ManualResetEvent may also be worth investigating.

Related

How can I share resources with threads in C#?

I have a thread reading from a specific plc's memory and it works perfectly. Now what I want is to start another thread to test the behavior of the system (simulate the first thread) in case of a conectivity issue, and when everything is Ok, continue the first thread. But I think I'll have problems with that because these two threads will need to use the same port.
My first idea was to abort the first thread, start the second one and when the everything's OK again, abort this thread and 'restart' the first one.
I've read some other forums and people say that aborting or suspending a thread is the worst solution, and I've read about syncronization of threads but I dont really know if this is useful in this case because I've never used it.
My question is, what is the correct way to solve this kind of situations?
You have a shared resource that you need to coordinate thread access to. There are a number of mechanisms in .NET available for that coordination.
There is a wonderful resource that provides both an introduction to thread concepts in .NET, and discusses advanced concepts in an approachable manner
http://www.albahari.com/threading/
In your case, have a look at the section on locking
Exclusive locking is used to ensure that only one thread can enter particular sections of code at a time. The two main exclusive locking constructs are lock and Mutex. Of the two, the lock construct is faster and more convenient. Mutex, though, has a niche in that its lock can span applications in different processes on the computer.
http://www.albahari.com/threading/part2.aspx#_Locking
You can structure your two threads so that they must acquire a specific lock to work with the port. Have your first thread release that lock before you start the second thread, then have the first thread wait to acquire that lock again (which the second thread will hold until done).

Monitor.Pulse in C# appears suboptimal : must be in lock scope

spoiler note: the question is the last phrase.
In C#, the classical pattern to use a condition variable is like this:
lock (answersQueue)
{
answersQueue.Enqueue(c);
Monitor.Pulse(answersQueue); // condition variable "notify one".
}
and some other thread:
lock (answersQueue)
{
while (answersQueue.Count == 0)
{
// unlock answer queue and sleeps here until notified.
Monitor.Wait(answersQueue);
}
...
}
that's an example taken from my code.
if I place the Pulse outside of the lock scope, it doesn't compile.
however, it is the correct way:
c.f:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms686903(v=vs.85).aspx
and:
http://www.installsetupconfig.com/win32programming/threadprocesssynchronizationapis11_7.html
(search for "inside")
And indeed it is idiotic to signal the sleeping thread when you still are in your critical section. Because the sleeping thread CAN'T wake up (not immediately), BECAUSE it is INSIDE a criticial section as well !
Therefore, I hope that .NET or C# Pulse call is actually just flagging the lock object, so that when it goes out of scope it actually "pulses" the condition variable at this moment. Because otherwise, it would have an optimality issue.
So how come the design of the Monitor object was chosen to be that way ?
Edit:
I found the answer in this paper:
http://research.microsoft.com/pubs/64242/implementingcvs.pdf
section "Optimising Signal and Broadcast" and the previous section about NT kernel and how to make Condition Variable on top of Semaphores, which is the reason for introducing the "darned queues".
NOW that makes me a better engineer.
And indeed it is idiotic to signal the sleeping thread when you still are in your critical section. Because the sleeping thread CAN'T wake up
Pulse doesn't expect to get a thread running; it only expects to move a thread between the 2 queues (waiting and ready). The "not go do something" is part of releasing the lock via Exit (or the end of a lock). In reality, it isn't an issue because Monitor.Pulse typically happens right before a Wait or an Exit.
Therefore, I hope that .NET or C# Pulse call is actually just flagging the lock object, so that when it goes out of scope it actually "pulses" the condition variable at this moment. Because otherwise, it would have an optimality issue.
Again; these are different issues: moving between waiting and ready is one thing; exiting a lock already has all the code to actually activate the next ready thread.
You did not understood the basic problem of synchronization. What is a 'monitor', what does it mean that a thread sleeps and what does it mean that it is about to be woken up?
A monitor is a mid-level synchronization structure. This is not a low-level petty volatile boolean flag with bus-halting XCHG operation, and this is not high-level thread pool handler that requires dozens of other special mechanisms..
On a monitor, MANY threads may sleep. There are logical queues out there that i.e. preserver order of being put to sleep/woken up, or mechanisms that guarantee proper time scheduling and fairnees. I will not get into details, all of it is out there on the web, even on wiki.
Add to that that the operation is PULSE. Pulse is instantenous. It does not "stick". Pulse will wake those now sleeping. If after the pulse another one check the monitor, it will go to sleep.
Now imagine: you have a queue of 5 sleeping threads. One thread (6th) wants now to pulse them, and yet another (7th) wants to check the monitor.
6th and 7th are running in parallel, truly simultaneously, since you have quad-core CPU.
So, tell me, what would happen to the queue's implementtion if the 6th starts pulsing andwaking and removing woken threads from the queue, and in the same time the 7th one starts adding itself there?
To solve that, the internal queues would have to be internally synchronized and locked, so only one thread at time modifies them.
Um wait. We just stumbled upon a case where we wanted to SYNCHRONIZE something, and to do it properly we need to SYNCHRONIZE on another thing? Not good.
Therefore, the actual LOCK is done EXTERNALLY before you talk to the monitor itself. This is to achieve SINGLE LOCKING, instead of introduce several layers of hierarchical locks.
That way it is simplier, faster, and more resource-friendly.

Monitor.TryEnter()

I was wondering on the Monitor Class.
As far as i know all waiting threads are not FIFO.
The first one that aquires the lock is not allways the first on in the waiting queue.
Is this correct?
Is there some way to ensure the FIFO condition?
Regards
If you are referring to a built-in way, then no. Repeatedly calling TryEnter in a loop is by definition not fair and unfortunately neither is the simple Monitor.Enter. Technically a thread could wait forever without getting the lock.
If you want absolute fairness you will need to implement it yourself using a queue to keep track of arrival order.
Is there some way to ensure the FIFO condition?
In a word: no!
I wrote a short article about this: Is the Ready Queue FIFO?
Look at this question, I think it will very useful for you - Does lock() guarantee acquired in order requested?
especially this quote:
Because monitors use kernel objects internally, they exhibit the same
roughly-FIFO behavior that the OS synchronization mechanisms also
exhibit (described in the previous chapter). Monitors are unfair, so
if another thread tries to acquire the lock before an awakened waiting
thread tries to acquire the lock, the sneaky thread is permitted to
acquire a lock.

C# threading deadlock

I have a multi-threaded program in C#. What is the best way to prevent deadlock in practice?
Is it timedlock?
Also, what is the best tool available to help detect and prevent the deadlock?
Thank you very much.
Deadlocks typically occur in a few scenarios:
You are using several locks and not locking/unlocking them in the correct order. Hence, you may create a situation where a thread holds lock A and needs lock B, and another thread needs lock A and holds lock B. Neither of them can proceed. This is because each thread is locking in a different order.
When using a reentrant lock and locking it more times than you are unlocking it. See this related question: why does the following code result in deadlock
When using Monitor.Wait/Monitor.Pulse as a signaling mechanism, but the thread that must call Wait does not manage to reach the call by the time the other thread has called Pulse and the signal is lost. You can use the AutoResetEvent for a persistent signal.
You have a worker thread polling a flag to know when to stop. The main thread sets the flag and attempts to join the worker thread, but you forgot to make the flag volatile.
It's not C# specific. You should always acquired in some well-defined order.
There is much information in internet, for example, you might take a look here
http://www.javamex.com/tutorials/threads/deadlock.shtml

Is ReaderWriterLockSlim.EnterUpgradeableReadLock() essentially the same as Monitor.Enter()?

So I have a situation where I may have many, many reads and only the occasional write to a resource shared between multiple threads.
A long time ago I read about ReaderWriterLock, and have read about ReaderWriterGate which attempts to mitigate the issue where many writes coming in trump reads and hurt performance. However, now I've become aware of ReaderWriterLockSlim...
From the docs, I believe that there can only be one thread in "upgradeable mode" at any one time. In a situation where the only access I'm using is EnterUpgradeableReadLock() (which is appropriate for my scenario) then is there much difference to just sticking with lock(){}?
Here's the excerpt:
A thread that tries to enter
upgradeable mode blocks if there is
already a thread in upgradeable mode,
if there are threads waiting to enter
write mode, or if there is a single
thread in write mode.
Or, does the recursion policy make any difference to this?
Agreed. If all of your threads need to acquire an upgradable read lock and you cannot afford to release a read lock and acquire a write lock then ReaderWriterLockSlim is no improvement over a simple exclusive lock. Recursion does not change that. RWLS and the need to avoid the ever present danger of deadlock heavily favors a pattern where a single thread does the writing.
I don't have all your answers, but I'll give it a shot:
The lock statement in c# is syntactic sugar for calling Monitor.Enter and Monitor.Exit. The effect is that only one thread can access the code within the lock at a time.
lock()
{
//only one thread can access this code at a time
}
The issue with this is that multiple reads are harmless, but lock() blocks anyway. ReaderWriterLockSlim allows multiple reads, only one write. It's an attempt to improve efficiency.
The recursion policy is something you must specify - by default it is off. Don't know too much more beyond that, but hope that helps a little.

Categories