I have a part of code in an Async/Await function that I only want one thread to execute at a time.
This is relatively simple by creating a new SemaphoreSlim(1) and using WaitAsync/Release. The effect is that the first thread executes while the others wait and then execute one by one.
What I am trying to achieve is actually slightly different. I would like the other threads not to wait, but to return out of the function (i.e. I don't want to block the other threads). So if there was a property "NumberOfThreadsCurrentlyExecuting" I would effectively have an If Semaphore.NumberOfThreadsCurrentlyExecuting > 0 Then Return.
But such a property doesn't exist. Does anyone have any idea for a way around this problem?
Thanks
Charles
How about using the SemaphoreSlim.Wait/Async with a zero-timeout? If it can't enter the semaphore (because it's already been entered), it will return false.
Note that Monitor (and thus lock) is completely unsuited to async
(hence the fact that you can't await in a lock) because
your task may continue on another thread after you've entered the lock (thus you will try to release the lock from another thread)
after you've awaited, another continuation may use your thread (while it is still holding the lock), so if it attempts to acquire the lock it will succeed
Instead of a Semaphore, you could just use a Monitor.
If you call TryEnter and it fails, another thread is in the "lock".
This is thread safe (unlike checking semaphore counts), and fairly simple:
// using somethign like: object sync = new object();
bool lockTaken = Monitor.TryEnter(sync);
try
{
if (lockTaken)
{
// You're here - do your work
}
else
{
// Something else was in the thread - exit?
return;
}
}
finally
{
if (lockTaken) Monitor.Exit(sync);
}
Related
I am making a library that allows access to a system-wide shared resource and would like a mutex-like lock on it. I have used the Mutex class in the past to synchronize operations in different threads or processes.
In UI applications a problem can occur. The library I'm making is used in multiple products, of which some are plugins that sit in the same host UI application. Because of this, the UI thread is the same for each instance of the library - so mutex.WaitOne() will return true even if the resource is already being accessed.
The 'resource' is the user's attention. I don't want more than one specific child window open regardless of which host process wants to open it. Additionally, it may be a different thread that knows when the mutex can be released (child window closed).
Is there a class, or pattern I can apply, that will allow me to easily solve this?
To summarize my intentions, this might be the ideal fictional class:
var specialMutex = new SpecialMutex("UserToastNotification");
specialMutex.WaitOne(0); // Returns true only once, even on the same thread,
// and is respected across different processes.
specialMutex.Release(); // Can be called from threads other than the one
// that called WaitOne();
Yes, Release looks dangerous, but it's only called by the resource.
I think you want a Semaphore that has an initial value of 1. Any call to WaitOne() on a Semaphore tries to decrement the count, regardless of the thread. And any call to Release, regardless of the thread that calls it, results in incrementing the count.
So if a single thread initializes a semaphore with a value of 1 and then calls WaitOne, the count will go to 0. If that same thread calls WaitOne again on the same semaphore, the thread will lock waiting for a release.
Some other thread could come along and call Release to increment the count.
So, whereas a Semaphore isn't exactly like a Mutex, it might be similar enough to let your program work.
You could use a compare/exchange operation to accomplish this. Something like this:
class Lock {
int locked = 0;
bool Enter() { return Interlocked.CompareExchange(ref locked, 1, 0) == 0; }
void Leave() { Interlocked.CompareExchange(ref locked, 0, 1); }
}
Here, Enter will only ever return true once, regardless from which thread it is called, untill you call leave.
Background
I am trying to write an application that does the following:
I make a method call to SomeBlockingMethod.
This method calls blocks until I call SomeUnblockingMethod from another thread.
When SomeUnblockingMethod is called, the routine inside of SomeBlockingMethod will continue.
Note, the first thing I do will be to call the SomeBlockingMethod, and then later on I will call the SomeUnblockingMethod. I am thinking about using a Monitor.Wait/Monitor.Pulse mechanism to achieve this. The only thing is, when one calls Monitor.Wait, you cannot block initally unless the object involved has already been locked by something else (or at least not that I know of)... But, I want blocking to be the first thing I do... So this leads me into my question...
Question
Is there some way I can implement Monitor.Wait to initially block until a call to Monitor.Pulse is made?
You can use AutoResetEvent instead.
AutoResetEvent ar = new AutoResetEvent(false); // false set initial state as not signaled
Then you can use ar.WaitOne() to wait and ar.Set() to signal waiting processes.
You should use Monitor when you want to protect a resource or you have a critical section. If you want to have a signaling mechanism then AutoResetEvent or ManualResetEvent sounds like a better option.
I don't know what is the problem, but what you want is already how it works:
object _lock = new object();
void SomeBlockingMethod()
{
lock(_lock)
Monitor.Wait(_lock);
... // here only after pulse
}
void SomeUnblockingMethod()
{
lock(_lock)
Monitor.Pulse(_lock);
}
Perhaps you are calling SomeBlockingMethod from multiple places, then you want to use PulseAll. Or perhaps SomeUnblockingMethod is called before SomeBlockingMethod?
I am developing an app for windows phone 7.Now I have 2 threads.
thread 1
lock(somelock)
{
//does some work
Monitor.Wait();
//Does some work
}
thread 2
lock(somelock)
{
//does some work
Monitor.Signal();
//does some work;
}
Now I want to know whether Monitor.wait() signals the other thread.
A thread that fails to get a lock is held in the ready queue. If the thread with the lock calls Wait, then it yields the lock and any threads in the ready-queue are eligible to be activated, obtaining the lock. So in a way they are activated, but they aren't "pulsed", if that is what you mean by signalled.
By contrast, the thread that voluntarily called Wait is in a separate queue; it doesn't become activated just by a thread yielding the lock; the only way that thread gets back into the ready queue is if either a thread with the lock calls Pulse/PulseAll, or the timeout occurs. Note that Pulse/PulseAll do not yield the lock - they just more a thread/threads from the sleeping queue to the ready-queue. The lock in the second example is only yielded when leaving the lock statement. As a consequence of this, note that the "does some work" after the Pulse (Signal in your example) is still done while holding an exclusive lock (in effect, you might as well move the Pulse to the end of the lock statement).
No, but Monitor.Pulse() does. Use Monitor.Pulse() when you want to signal that the state may have changed for a Monitor.Wait() condition.
http://www.albahari.com/threading/part4.aspx#_Signaling_with_Wait_and_Pulse
I have a multi thread application.
One thread inserts in a queue and many thread reads form this queue. In order to read properly, reader threads lock the queue like the following code.
My question is: Does the inserter thread become blocked when the following code is called by reader threads since it uses the same queue? Or it continues inserting without interruption?
lock ( MsgQueue ) {
if ( MsgQueue.Count == 0 ) {
Monitor.Wait( MsgQueue );
continue;
}
msg = MsgQueue.Dequeue( );
}
The other thread will be blocked by the lock (MsgQueue) while this thread is in the lock but not when in the Monitor.Wait (which releases the lock so other threads can Pulse).
This is the conditional variable pattern: hold the lock while working on the shared state (the queue instance), but release it while waiting for the condition to change (the Monitor.Wait).
Update: based on comment:
No it inserts simply. There is no lock for inserter
Then the queue object is likely to be corrupted. Unless the queue type you are using is inherently thread-safe you must use the same lock for all operations.
Update #2: If this queue is primarily being used to transfer objects from one set of (source) threads to another set of (worker) threads (where each set might just be one) then you should consider a ConcurrentQueue which is thread safe (albeit you will need something like an event to signal there is something on the queue to avoid workers polling).
Yes, the producer (or inserter) will be blocked while the lock is held by the consumer. Note that the lock is released by a call to Monitor.Wait and then reacquired when control flow has returned back to the caller. All of this assumes your producer attempts to acquire the same lock.
As a side note, the way you have the consumer coded is slightly less efficient than it could be. Because you have a continue statement I have to assume that a while loop wraps the lock which probably makes your code look more like the following.
object msg = null;
while (msg == null)
{
lock (MsgQueue)
{
if (MsgQueue.Count == 0)
{
Monitor.Wait(MsgQueue);
continue;
}
msg = MsgQueue.Dequeue();
}
}
This could be refactored so that the wait condition is rechecked inside the lock block. This way you do not have to release and reacquire the lock to perform the check.
object msg = null;
lock (MsgQueue)
{
while (MsgQueue.Count == 0)
{
Monitor.Wait(MsgQueue);
}
msg = MsgQueue.Dequeue();
}
Again, because I see the continue statement I am assuming you are aware that the wait condition must always be rechecked after a Wait. But, just in case you are not aware of this requirement I will state it here because it is important.
If the wait condition is not rechecked and there is 2 or more consumers then one of them could get inside the lock and dequeue the last item. This could still happen even if the other consumer were moved from the waiting queue to the ready queue via a call to Pulse or PulseAll, but it did not get a chance to reacquire the lock before the first consumer. Obviously, without the recheck a consumer could attempt to operate on an empty queue. It does not matter whether Pulse or PulseAll is used on the producing side. There is still a problem because the Monitor does not give preference to a Wait above an Enter.
Update:
I forgot to point out that if you are using .NET 4.0 then you can take advantage of BlockingCollection which is an implementation of a blocking queue. It is safe for multiple producers and consumers and does all of the blocking for you if the queue is empty.
The inserter thread is being blocked at points, yes.
lock ( MsgQueue ) {
if ( MsgQueue.Count == 0 ) { // LINE 1
Monitor.Wait( MsgQueue ); // LINE 2
continue;
}
msg = MsgQueue.Dequeue( ); // LINE 3
}
At line 1 the lock is held by the reader, so the inserter is blocked.
At line 2 the lock is released, and not reacquired until the inserter presumably calls Monintor.Pulse on MsgQueue.
At line 3 the lock is still being held (from line 1), and afterwards it is released again due to exiting the lock scope.
If the inserter thread calls lock ( MsgQueue ) then obviously it will block whenever one of the readers has locked the queue
No. I think your questuon is about the meaning of lock ( MsgQueue ) and the metaphor can be a bit misleading. Locking on an object does not change the state of that object in any way, nor does it block other threads, unless those threads use lock on the same object too.
That's why you often see this (better) pattern:
private Queue<MyClass> _queue = ...;
private object _queueLock = new object();
...
lock(_queueLock )
{
_queue.Enqueue(item);
}
The reference used in the lock only serves as a 'ticket'.
I suspect this is a very dumb question: what is the correct syntax for an interruptible lock statement in C#? E.g. get lock; if lock is interrupted before locked code finishes, return false out of the enclosing method. Probably totally the wrong terminology... Thanks.
You can have a timeout while aquiring a lock using Monitor.TryEnter; and likewise, within a lock you can do things like Monitor.Wait/Monitor.Pulse to temporarily yield the lock, but you can't be interrupted as such.
The main time interrupt applies might be in Thread.Sleep, which can be interrupted with Thread.Interrupt - but again, this won't yank control out of an executing method block.
What exactly is it that you are trying to achieve? With more context we can probably help more...
What you mean by "interrupted" is unclear.
Interruption by Exception
private bool SomeLockingMethod(object foo)
{
// Verify foo is valid
try
{
lock(foo)
{
while(something)
{
// Do stuff
Thread.Sleep(1); // Possibly yield to another
// thread calling Thread.Interrupt
}
}
return true;
}
catch(ThreadInterruptedException ex)
{
// Handle exception
}
return false;
}
If the return true isn't reached, then something happened while the lock on foo was held, and the code returns false. The lock is automatically released, either way.
Another thread can interrupt this one by calling Thread.Interrupt.
"Interruption" from code
If you're the one "interrupting" the code, it could be as simple as
private bool SomeLockingMethod(object foo)
{
// Verify foo is valid
lock(foo)
{
// Do stuff
if(shouldInterrupt)
{
return false;
}
// Do more stuff
}
return true;
}
Again, the lock is automatically released, whether or not there is an "interruption".
Interruption because someone else is trying to acquire the lock
Possibly this is what you're looking for; in this case you may want to use something else, like a Semaphore or ManualResetEvent.
I'm not sure what you're trying to get at here. The purpose of the lock statement is that you should not get interrupted so you can ensure consistent behavior.
What are you trying to accomplish here?
You might also have a look at transaction scope, added in 2.0, which may be what you're looking for (unknown, due the ambiguity in your question). It allows you to attempt some actions, then roll back if those actions were not completed properly.
See here for more details.