.NET Threading - Synchronization Object - c#

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'.

Related

C# WPF, Multi-Threads for Queue

Thread1 does Enqueue()
Thread2, 3 does Dequeue()
Thread 2, 3 has same mutex, when i used different mutex, sometime dequeue works twice.
When i use same mutex in Thread 1,2,3 it works fine. What is difference between using same mutex in Thread 1,2,3 and thread1_mutex for Thread1, thread2_mutex for Thread 2,3?
How to prevent dequeue (Thread 2 and 3) working twice for same value?
if dequeue works twice for same value, it prints twice in my WPF Textbox. I want to make it null for later Dequeue value.
public class NewData
{
public int seq;
public int data;
public NewData()
{
}
public NewData(int seq, int data)
{
this.seq = seq;
this.data = data;
}
}
private void Thread1()
{
while (true)
{
for (int i = 1; i <= threadRunningTime / threadSleep; i++)
{
NewData newData = new NewData(i, random.Next(100));
thread1_mutex.WaitOne();
queue.Enqueue(newData);
thread1_mutex.ReleaseMutex();
Thread.Sleep(threadSleep);
}
}
}
private void Thread2()
{
while (true)
{
NewData newData = new NewData();
thread2_mutex.WaitOne();
if (queue.Count != 0)
{
newData = queue.Dequeue();
}
else
{
newData = null;
}
thread2_mutex.ReleaseMutex();
Thread.Sleep(threadSleep);
}
}
private void Thread3()
{
while (true)
{
NewData newData = new NewData();
thread2_mutex.WaitOne();
if (queue.Count != 0)
{
newData = queue.Dequeue();
}
else
{
newData = null;
}
thread2_mutex.ReleaseMutex();
Thread.Sleep(threadSleep);
}
}
When i use same mutex in Thread 1,2,3 it works fine. What is difference between using same mutex in Thread 1,2,3 and thread1_mutex for Thread1, thread2_mutex for Thread 2,3?
The difference is that using different mutexes would allow one thread to enqueue an item at the same time another thread dequeues an item. Since the Queue class is not thread safe this is not allowed, and just about anything may happen if you do this. You must use a single mutex to prevent concurrent access, with the exception of concurrent read only access. But both enqueue and dequeue needs to write things, so that is not relevant in this case.
How to prevent dequeue (Thread 2 and 3) working twice for same value? if dequeue works twice for same value, it prints twice in my WPF Textbox. I want to make it null for later Dequeue value.
I would assume this is due to the issue above. If only a single thread has exclusive access to the queue you should not be getting duplicates. Note that any updates of the UI must be done from the UI thread. So if you are reading values from multiple threads you will need a thread safe way to hand these values over to the UI thread for display. In some sense, console programs may be easier to use for demonstration, since Console.WriteLine is thread safe.
I would also recommend using the lock statement instead of mutex. The former is both easier to use and should perform better. The only real use case I know for mutex is to provide synchronization across multiple processes, and that is a fairly rare thing to do. Ofcource, even better would be to use a concurrentQueue, but I'm assume that goes against the spirit of the assignment. Note that "mutex" may be used either as an abstract concept, i.e. to provide exclusive access to a resource, or to the specific mutex class in .net. So there may be some confusion about the terms used.
When Thread3 wins the race and calls Mutex.WaitOne before Thread2, then Thread2 must wait until Thread3 has released the mutex by calling Mutex.ReleaseMutex.
If Thread3 has finally released the mutex, Thread2 will be able to continue execution.
This is called a mutual exclusive (short mutex) lock or synchronization mechanism.
If you had used a dedicated mutex for each thread, then the threads won't be able to lock each other out and therefore both threads can access the shared resource at the same time (concurrently).
You need at least two participants for a mutual relationship.
In other words: if you want to synchronize access to a shared resource e.g., a Queue, in order to prevent undefined behavior like the dequeuing of the same element by different threads, all the accessing threads must be using the same mutex instance in order to be able lock each other out (mutually). That's the essence of synchronization.
Each mutex instance represents a new waiting queue for the threads.
If multiple threads share the same resource, they must also share the same waiting queue.
This is true for every synchronization mechanism.

Proper locking pattern

I'm facing a little problem with locks in C# (but no matter the language, it's more an algorithmic question).
When I enter in a method, I take a read lock on an object. But if the given object is null (not initialized), I need to initialize it. So, I need to get a write lock on it. But, the problem is that I am already in a read lock zone.
Ex:
public string LocalUid
{
get
{
using (new ReadLock(MongoDBConnector.adminLock))
{
MongoClient mongo = MongoDBConnector.GetAdminClient();
// Do something...
}
}
return localUid;
}
return null;
}
}
and the GetAdminClient method is:
public static MongoClient GetAdminClient()
{
if (adminClient == null)
{
using (new WriteLock(adminLock))
{
if (adminClient == null) // Double check locking pattern
{
adminClient = CreateAdminClient();
}
}
}
return adminClient;
}
So we clearly see that the writelock is asked in a readlocked zone :(
Any idea / best practice for this case ?
This is a common pattern known as lock escalation. You have to be very careful to avoid deadlocks caused by lock escalation:
Thread A acquires read lock on Resource X.
Thread B acquires read lock on Resource X (this is allowed because Thread A only has a read lock).
Thread A wants to escalate its read lock to a write lock on Resource X, but it has to wait for Thread B to first release its read lock.
Thread B wants to escalate its read lock to a write lock on Resource X, but it has to wait for Thread A to first release its read lock.
Threads A and B are now deadlocked.
This type of deadlock can be avoided by taking a write lock to begin with, i.e., take a write lock when reading if the result of the read may require you to later take a write lock.

Skip SemaphoreSlim instead of wait

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);
}

How do I maintain a fixed collection of threads?

Need suggestion for best approach for Multi-threading in c# 3.0 (No Parallel or Task)
The situation is, I have a Queue with 500 items. At a particular time I can run only 10 threads (Max). Below is my code.
While (queue.Count > 0)
{
Thread[] threads = new Thread[no_of_threads];
for (int j = 0; j < no_of_threads; j++)
{
threads[j] = new Thread(StartProcessing);//StartProcessing Dequeue one item each time //for a single thread
threads[j].Start();
}
foreach (Thread objThread in threads)
{
objThread.Join();
}
}
Problem in this approach is, for an instance, if no_of_threads = 10 and out of them 9 threads are done with processing, and 1 thread is still working, I cannot come out of loop and delegate work to the free threads until all 10 threads are done.
I need at all the time 10 threads should work till the queue count > 0.
This is easily done with a Semaphore.
The idea is to create a semaphore with a maximum count of N, where N is the number of threads you allow. The loop waits on the semaphore and queues tasks as it acquires the semaphore.
Semaphore ThreadsAvailable = new Semaphore(10, 10);
while (Queue.Count > 0)
{
ThreadsAvailable.WaitOne();
// Must dequeue item here, otherwise you could run off the end of the queue
ThreadPool.QueueUserWorkItem(DoStuff, Queue.Dequeue());
}
// Wait for remaining threads to finish
int threadCount = 10;
while (threadCount != 0)
{
ThreadsAvailable.WaitOne();
--threadCount;
}
void DoStuff(object item)
{
ItemType theItem = (ItemType)item;
// process the item
StartProcessing(item);
// And then release the semaphore so another thread can run
ThreadsAvailable.Release();
}
The item is dequeued in the main loop because that avoids a race condition that otherwise is rather messy to handle. If you let the thread dequeue the item, then the thread has to do this:
lock (queue)
{
if (queue.Count > 0)
item = queue.Dequeue();
else
// There wasn't an item to dequeue
return;
}
Otherwise, the following sequence of events is likely to occur when there is only one item left in the queue.
main loop checks Queue.Count, which returns 1
main loop calls QueueUserWorkItem
main loop checks Queue.Count again, which returns 1 because the thread hasn't started yet
new thread starts and dequeues an item
main loop tries to dequeue an item and throws an exception because queue.Count == 0
If you're willing to handle things that way, then you're okay. The key is making sure that the thread calls Release on the semaphore before the thread exits. You can do that with explicitly managed threads, or with the ThreadPool approach that I posted. I just used ThreadPool because I find it easier than explicitly managing threads.
So all you need to handle this is a queue that is designed to be accessed from multilpe threads. Were you using .NET 4.0 I'd say use BlockingCollection. Not only will it work perfectly, but it's very efficient. You can rather trivially make your own class that is just a Queue with lock calls around all of the methods. It will work about as well, but it won't be as efficient. (It will likely be efficient enough for your purposes though, and a re-writing BlockingCollection "properly" would be quite hard.)
Once you have that queue each worker can just grab an item from that queue, process it, then ask the queue for another. When there are no more you don't need to worry about ending that thread; there's no more work it could do.
You should use ThreadPool which manages and optimizes threads for you
Once a thread in the pool completes its task, it is returned to a queue of waiting threads, where it can be reused. This reuse enables applications to avoid the cost of creating a new thread for each task.
Thread pools typically have a maximum number of threads. If all the threads are busy, additional tasks are put in queue until they can be serviced as threads become available.
It's better not to interfere into ThreadPool since it's enough smart to manage and allocate threads. But if you really need to do this, you can set the constraint of the maximum number of threads by using SetMaxThreads method
Instead of controlling the threads from the outside, let each thread consume data itself.
Pseudocode:
create 10 threads
thread code:
while elements in queue
get element from queue
process element
This is a simple producer-consumer scenario. You need a thread-safe queue like this one: Creating a blocking Queue<T> in .NET? - 10 threads can read and process job by job in a loop until the queue is empty.
Depending on how you fill the queue (prior to starting processing it or while processing it) you can end those threads as soon as the queue becomes empty or when you signal it to stop by means of a stop flag. In the latter case you probably need to wake the threads (eg with dummy jobs).

Does lock(){} lock a resource, or does it lock a piece of code?

I'm still confused... When we write some thing like this:
Object o = new Object();
var resource = new Dictionary<int , SomeclassReference>();
...and have two blocks of code that lock o while accessing resource...
//Code one
lock(o)
{
// read from resource
}
//Code two
lock(o)
{
// write to resource
}
Now, if i have two threads, with one thread executing code which reads from resource and another writing to it, i would want to lock resource such that when it is being read, the writer would have to wait (and vice versa - if it is being written to, readers would have to wait). Will the lock construct help me? ...or should i use something else?
(I'm using Dictionary for the purposes of this example, but could be anything)
There are two cases I'm specifically concerned about:
two threads trying to execute same line of code
two threads trying to work on the same resource
Will lock help in both conditions?
Most of the other answers address your code example, so I'll try to answer you question in the title.
A lock is really just a token. Whoever has the token may take the stage so to speak. Thus the object you're locking on doesn't have an explicit connection to the resource you're trying to synchronize around. As long as all readers/writers agree on the same token it can be anything.
When trying to lock on an object (i.e. by calling Monitor.Enter on an object) the runtime checks if the lock is already held by a thread. If this is the case the thread trying to lock is suspended, otherwise it acquires the lock and proceeds to execute.
When a thread holding a lock exits the lock scope (i.e. calls Monitor.Exit), the lock is released and any waiting threads may now acquire the lock.
Finally a couple of things to keep in mind regarding locks:
Lock as long as you need to, but no longer.
If you use Monitor.Enter/Exit instead of the lock keyword, be sure to place the call to Exit in a finally block so the lock is released even in the case of an exception.
Exposing the object to lock on makes it harder to get an overview of who is locking and when. Ideally synchronized operations should be encapsulated.
Yes, using a lock is the right way to go. You can lock on any object, but as mentioned in other answers, locking on your resource itself is probably the easiest and safest.
However, you may want use a read/write lock pair instead of just a single lock, to decrease concurrency overhead.
The rationale for that is that if you have only one thread writing, but several threads reading, you do not want a read operation to block an other read operation, but only a read block a write or vice-versa.
Now, I am more a java guy, so you will have to change the syntax and dig up some doc to apply that in C#, but rw-locks are part of the standard concurrency package in Java, so you could write something like:
public class ThreadSafeResource<T> implements Resource<T> {
private final Lock rlock;
private final Lock wlock;
private final Resource res;
public ThreadSafeResource(Resource<T> res) {
this.res = res;
ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
this.rlock = rwl.readLock();
this.wlock = rwl.writeLock();
}
public T read() {
rlock.lock();
try { return res.read(); }
finally { rlock.unlock(); }
}
public T write(T t) {
wlock.lock();
try { return res.write(t); }
finally { wlock.unlock(); }
}
}
If someone can come up with a C# code sample...
Both blocks of code are locked here. If thread one locks the first block, and thread two tries to get into the second block, it will have to wait.
The lock (o) { ... } statement is compiled to this:
Monitor.Enter(o)
try { ... }
finally { Monitor.Exit(o) }
The call to Monitor.Enter() will block the thread if another thread has already called it. It will only be unblocked after that other thread has called Monitor.Exit() on the object.
Will lock help in both conditions?
Yes.
Does lock(){} lock a resource, or does
it lock a piece of code?
lock(o)
{
// read from resource
}
is syntactic sugar for
Monitor.Enter(o);
try
{
// read from resource
}
finally
{
Monitor.Exit(o);
}
The Monitor class holds the collection of objects that you are using to synchronize access to blocks of code.
For each synchronizing object, Monitor keeps:
A reference to the thread that currently holds the lock on the synchronizing object; i.e. it is this thread's turn to execute.
A "ready" queue - the list of threads that are blocking until they are given the lock for this synchronizing object.
A "wait" queue - the list of threads that block until they are moved to the "ready" queue by Monitor.Pulse() or Monitor.PulseAll().
So, when a thread calls lock(o), it is placed in o's ready queue, until it is given the lock on o, at which time it continues executing its code.
And that should work assuming that you only have one process involved. You will want to use a "Mutex" if you want that to work across more then one process.
Oh, and the "o" object, should be a singleton or scoped across everywhere that lock is needed, as what is REALLY being locked is that object and if you create a new one, then that new one will not be locked yet.
The way you have it implemented is an acceptable way to do what you need to do. One way to improve your way of doing this would be to use lock() on the dictionary itself, rather than a second object used to synchronize the dictionary. That way, rather than passing around an extra object, the resource itself keeps track of whether there's a lock on it's own monitor.
Using a separate object can be useful in some cases, such as synchronizing access to outside resources, but in cases like this it's overhead.

Categories