synchronize two methods and avoid to run simultaneously - c#

class1 has two methods, do1 and do2.
It is instanciated from multiple thread in the same application.
i need to synchronize two methods with this specs:
do1 can be executed only from 1 thread at time, lock would be a good solution.
do2 can be called from multiple thread at the same time but
it cannot be called when do1 is running.
When do1 is called evary thread must wait the completion of do1 before to start do2.
Thanks.

There are basically two ways to accomplish this. One is with a Semaphore with one method that takes all available slots with one method, and another that uses one slot per execution attempt. That's a bit of a hack, though, what you really need is a synchronization object that allows exclusive and non-exclusive locks.
That's what ReaderWriterLock and ReaderWriterLockSlim do. They're designed for cases where you need exclusive write access to a resource but non-exclusive read access to the resource, and work well for these sort of scenarios:
ReaderWriterLockSlim m_lock = new ReaderWriterLockSlim();
public string do2()
{
m_lock.EnterReadLock();
try
{
// Do work, many threads can enter this lock at the same time
}
finally
{
m_lock.ExitReadLock();
}
}
public void do1()
{
m_lock.EnterWriteLock();
try
{
// Do work, only one thread can be in here at once
}
finally
{
m_lock.ExitWriteLock();
}
}

If I understood the question correctly, the problem can be solved by simply using a private static lock object to synchronize the methods, which can be done as follows.
public class c1
{
private static iLock = new object();
public void do1()
{
lock (iLock)
{
// actual method body
}
}
public void do2()
{
lock (iLock)
{
// actual method body
}
}
}

Related

Why do my threads become deadlocked C#?

I'm having problems with multi-threading in an application I'm working on at the minute.
The process basically involves a list of items which need to be processed. As part of this processing a call needs to be made to a 3rd party api which does not support multi threading.
I've attempted to introduce a singleton instance of the API class and use locking to ensure that only one thread makes a call to it at once but I still get a situation were one thread gets stuck on the call to the API and the others are then stuck waiting on the lock to be released.
If I pause the debug session and check the callstack for the threads the one that has made it to the API call has the following trace:
mscorlib.dll!System.Threading.WaitHandle.WaitAll(System.Threading.WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
mscorlib.dll!System.Threading.WaitHandle.WaitAll(System.Threading.WaitHandle[] waitHandles)
I've tested this on a single thread by swapping out the thread pool in the foreach loop with an explicit call to the Process method and it works fine (although slower than I would like, there is quite a lot of processing before and after the API call).
Am I doing something wrong here or is this an issue with the third party api?
public class MyClass
{
private static ThirdPartyApi ApiInstance;
private static object lockObject = new object();
...
public void DoWork(list)
{
...
foreach (var item in list)
{
ThreadPool.QueueUserWorkItem(Process, item);
}
...
}
public void Process(string item)
{
// Various processing
...
lock(lockObject)
{
var result = ApiInstance.Lookup(item);
}
...
}
Code that is thread unsafe doesn't necessarily mean that the methods are not re-entrant, some thread-unsafe libraries require all calls to come from the same thread, period. Try the following method using a BlockingCollection instead, which will issue all calls on the same thread and see if it resolves the issue.
public class MyClass<T>
{
private BlockingCollection<T> workQueue = new BlockingCollection<T>();
public MyClass()
{
Task.Factory.StartNew(ProcessWorkQueue, TaskCreationOptions.LongRunning);
}
public void DoWork(List<T> work)
{
foreach (var workItem in work)
{
workQueue.Add(workItem);
}
}
public void StopWork()
{
workQueue.CompleteAdding();
}
public void ProcessWorkQueue()
{
foreach(var item in workQueue.GetConsumingEnumerable())
{
//Do something here
}
}
}
Also, the ThreadPool is a shared resource and performing any blocking action on a Threadpool thread can exhaust it. Even if your code did work, it would need to be refactored to address this resource starvation issue.

How do I perform both a read and a write of a boolean in one atomic operation?

Let's say I have a method that gets called by multiple threads
public class MultiThreadClass
{
public void Gogogo()
{
// method implementation
}
private volatile bool running;
}
in Gogogo(), I want to check if running is true, and if so, return from the method. However, if it is false, I want to set it to true and continue the method. The solution I see is to do the following:
public class MultiThreadClass
{
public void Gogogo()
{
lock (this.locker)
{
if (this.running)
{
return;
}
this.running = true;
}
// rest of method
this.running = false;
}
private volatile bool running;
private readonly object locker = new object();
}
Is there another way to do this? I've found out that if I leave out the lock, running could be false for 2 different threads, set to true, and the rest of the method would execute on both threads simultaneously.
I guess my goal is to have the rest of my method execute on a single thread (I don't care which one) and not get executed by the other threads, even if all of them (2-4 in this case) call Gogogo() simultaneously.
I could also lock on the entire method, but would the method run slower then? It needs to run as fast as possible, but part of it on only one thread at a time.
(Details: I have a dicionary of ConcurrentQueue's which contain "results" which have "job names". I am trying to dequeue one result per key in the dictionary (one result per job name) and call this a "complete result" which is sent by an event to subscribers. The results are sent via an event to the class, and that event is raised from multiple threads (one per job name; each job raises a "result ready" event on it's own thread)
You can use Interlocked.CompareExchange if you change your bool to an int:
private volatile int running = 0;
if(Interlocked.CompareExchange(ref running, 1, 0) == 0)
{
//running changed from false to true
}
I think Interlocked.Exchange should do the trick.
You can use Interlocked to handle this case without a lock, if you really want to:
public class MultiThreadClass
{
public void Gogogo()
{
if (Interlocked.Exchange(ref running, 1) == 0)
{
//Do stuff
running = 0;
}
}
private volatile int running = 0;
}
That said, unless there is a really high contention rate (which I would not expect) then your code should be entirely adequate. Using Interlocked also suffers a bit in the readability department due to not having bool overloads for their methods.
You need to use Monitor class instead of boolean flag. Use Monitor.TryEnter:
public void Gogogo()
{
if Monitor.TryEnter(this.locker)
{
try
{
// Do stuff
}
finally
{
Monitor.Exit(this.locker);
}
}
}

How to prevent a method from running across multiple threads?

I am working on a web application, where several users can update the same record. So to avoid a problem if users are updating the same record at the same time, I am saving their changes in a queue. When each save occurs, I want to call a method that processes the queue on another thread, but I need to make sure that the method cannot run in another thread if it is called again. I’ve read several posts on the subject, but not sure what is best for my situation. Below is the code I have now. Is this the correct way to handle it?
public static class Queue {
static volatile bool isProcessing;
static volatile object locker = new Object();
public static void Process() {
lock (locker) {
if (!isProcessing) {
isProcessing = true;
//Process Queue...
isProcessing = false;
}
}
}
}
New answer
If you are persisting these records to a database (or data files, or similar persistence system) you should let that underlying system handle the synchronization. As JohnSaunders pointed out Databases already handle simultaneous updates.
Given you want to persist the records… the problem presented by John is that you are only synchronizing the access to the data in a single instance of the web application. Still, there could be multiple instances running at the same time (for example in a server farm, which may be a good idea if you have high traffic). In this scenario using a queue to prevent simultaneous writes is not good enough because there is still a race condition among the multiple instances of the web page.
In that case, when you get updates for the same record from different instances, then the underlying system will have to handle the collision anyway, yet it will not be able to do it reliably because the order of the updates has been lost.
In addition to that problem, if you are using this data structure as a cache, then it will provide incorrect data because it is not aware of the updates that happen in another instance.
With that said, for the scenarios where it may be worth to use a Thread-Safe Queue. For those cases you could use ConcurrentQueue (as I mention at the end of my original answer).
I'll keep my original answer, because I see value in helping understand the threading synchronization mechanism available in .NET (of which I present a few).
Original answer
Using lock is enough to prevent the access of multiple threads to a code segment at the same time (this is mutual exclusion).
Here I have commented out what you don't need:
public static class Queue {
// static volatile bool isProcessing;
static /*volatile*/ object locker = new Object();
public static void Process() {
lock (locker) {
// if (!isProcessing) {
// isProcessing = true;
//Process Queue...
// isProcessing = false;
// }
}
}
}
The lock does NOT need volatile to work. However you might still need the variable to be volatile due to other code not included here.
With that said, all the threads that try to enter in the lock will be waiting in a queue. Which as I understand is not what you want. Instead you want all the other threads to skip the block and leave only one do the work. This can be done with Monitor.TryEnter:
public static class Queue
{
static object locker = new Object();
public static void Process()
{
bool lockWasTaken = false;
try
{
if (Monitor.TryEnter(locker))
{
lockWasTaken = true;
//Process Queue…
}
}
finally
{
if (lockWasTaken)
{
Monitor.Exit(locker);
}
}
}
}
Another good alternative is to use Interlocked:
public static class Queue
{
static int status = 0;
public static void Process()
{
bool lockWasTaken = false;
try
{
lockWasTaken = Interlocked.CompareExchange(ref status, 1, 0) == 0;
if (lockWasTaken)
{
//Process Queue…
}
}
finally
{
if (lockWasTaken)
{
Volatile.Write(ref status, 0);
// For .NET Framework under .NET 4.5 use Thread.VolatileWrite instead.
}
}
}
}
Anyway, you don't have the need to implement your own thread-safe queue. You could use ConcurrentQueue.
A lock is good but it won't work for async await. You will get the following error if you try to await a method call in a lock:
CS1996 Cannot await in the body of a lock statement
In this case you should use a SemaphoreSlim
Example:
public class TestModel : PageModel
{
private readonly ILogger<TestModel> _logger;
private static readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1);
public TestModel(ILogger<TestModel> logger)
{
_logger = logger;
}
public async Task OnGet()
{
await _semaphoreSlim.WaitAsync();
try
{
await Stuff();
}
finally
{
_semaphoreSlim.Release();
}
}
}
It is important to not new SemaphoreSlim in the constructor or anywhere else because then it won't work.
https://stackoverflow.com/a/18257065/3850405
https://learn.microsoft.com/en-us/dotnet/api/system.threading.semaphoreslim?view=net-5.0

use the same lock object at two different code block?

Can I use the same lock object at two methods, accessed by two different threads? Goal is to make task1 and task2 thread safe.
object lockObject = new object();
// Thread 1
void Method1()
{
lock(lockObject)
{
// task1
}
}
// Thread 2
void Method2()
{
lock(lockObject)
{
// task2
}
}
Yes, you can use the same lock object (it's technically a monitor in the computer science sense, and is implemented with calls to methods in System.Monitor) in two different methods.
So, say that you had some static resource r, and you wanted two threads to access that resource, but only one thread can use it at a time (this is the classic goal of a lock). Then you would write code like
public class Foo
{
private static object _LOCK = new object();
public void Method1()
{
lock (_LOCK)
{
// Use resource r
}
}
public void Method2()
{
lock (_LOCK)
{
// Use resource r
}
}
}
You need to lock around every use of r in your program, since otherwise two threads can use r at the same time. Furthermore, you must use the same lock, since otherwise again two threads would be able to use r at the same time. So, if you are using r in two different methods, you must use the same lock from both methods.
EDIT: As #diev points out in the comments, if the resource were per-instance on objects of type Foo, we would not make _LOCK static, but would make _LOCK instance-level data.
If you want to prevent different threads from performing task1 and task2 at the same time, then you must use the same lock object.
If the two tasks do not contend for the same resources, you could use different lock objects.
Yes.
You can and it works. If you don't use the same object, the blocks could execute at the same time. If you do use the same object, they can't.
Also, you mean lock(lockObject), not using(lockObject).

Recursive / nested locking in C# with the lock statement [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Re-entrant locks in C#
I've looked here on StackOverflow and on MSDN, and can't believe that I couldn't find this question lingering out there on the internets.
Let's say I have a class with a private member that I want to access in several public methods. These public methods will be called by different threads, hence the need for synchronization.
public class MyClass
{
private Object SomeSharedData = new Object();
public void MethodA()
{
lock( SomeSharedData) {
// do something
MethodB();
}
}
public void MethodB()
{
lock( SomeSharedData) {
// do something
}
}
}
Note that MethodA and MethodB can be called by users of this class, but MethodA also calls MethodB, which results in a nested locking condition.
Is this guaranteed to be safe? In other words, does .NET handle this by reference counting the lock, so that as I pop out of these methods, the lock gets decremented? Or is .NET performing some magic behind the scenes, whereby it simply ignores all subsequent locks on the object originating from the same thread?
Yes, locks based on Monitor in .NET are recursive, and counted.
From the docs for Monitor.Enter:
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.
Whether this is a good thing or not is up for debate...
Yes, Monitor support recursion, but you should be aware because this behavior differs from one synchronization primitive to another.
For example, ReaderWriterLockSlim by default doesn't support recursion and this code snippet throws exception:
public class MyClass
{
ReaderWriterLockSlim rw = new ReaderWriterLockSlim();
//You should explicitly stated that you want to use recursion
ReaderWriterLockSlim rwWithRecursion = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
public void MethodA()
{
try {
rw.EnterReadLock();
// do something
MethodB();
}
finally {
rw.ExitReadLock();
}
}
public void MethodB()
{
try {
rw.EnterReadLock(); //throws LockRecursionException
}
finally {
rw.ExitReadLock();
}
}
}

Categories

Resources