I have a C# class that executes an infinite loop until a conditional variable is set to true. There's another class that waits for a network message and when the message is received there's a call to the other class to modify the conditional variable to true so it can exit the while loop. The waiting for the message is done in a separate thread:
The modifier class:
public class Modifier{
Otherclass log;
private static NetworkStream theStream;
private StreamReader theInput;
public Modifier(Otherclass other, NetworkStream str)
{
this.log = other;
theStream = str;
theInput = new StreamReader(theStream);
Thread listenThread = new Thread(new ThreadStart(listen));
listenThread.Start();
}
public void listen()
{
while (true)
{
log.postMessage(theInput.ReadLine());
}
}
}
And the other class:
public class Otherclass{
bool docontinue = true;
public void postMessage(string input)
{
docontinue = true;
}
public void wait()
{
while(!docontinue)
{
}
}
}
The problem is that the program gets stuck at the while(!docontinue) although a message is sent. I suspect that the problem is that the variable docontinue is not getting modified but I don't know if the problem is somewhere else.
There are various issues here -
The first, and direct answer to your question, is that you need to declare your boolean field using volatile:
private volatile bool doContinue = true;
That being said, having a loop that does a while loop with no body is very bad - it will use up 100% CPU on that thread, and just "spin" indefinitely.
A much better approach to situations like this is to replace your while loop with a WaitHandle, such as ManualResetEvent. This allows you to wait on the reset event, and block until you're ready to continue. You call Set() on it in the other thread to allow the execution to continue.
For example, try this:
public class Otherclass{
ManualResetEvent mre = new ManualResetEvent(false);
public void PostMessage(string input)
{
// Other stuff here...
mre.Set(); // Allow the "wait" to continue
}
public void Wait()
{
mre.WaitOne(); // Blocks until the set above
}
}
You have two (potentially) infinite loops here. And nothing actually ever calls Wait()
Is there a good reason why you need to waste cycles in a dummy loop inside the wait method? What purpose does it serve?
It seems to me, postMessage should kick off a new thread that will perform whatever work needs to get done after Wait() is supposed to break.
You can use Volatile
private volatile bool docontinue = true;
Try adding Thread.Sleep(100) in your cycle. Also consider using the ManualResetEvent class.
UPDATE: I've just checked, wait() exits even without Thread.Sleep, volatile and other things. But my test console app hangs because the listen() thead never ends...
Other people have pointed out that there are better ways to do this, but I wanted to point out an issue in the code you posted.
public class Otherclass{
bool docontinue = true;
public void postMessage(string input)
{
docontinue = true;
}
public void wait()
{
while(!docontinue)
{
}
}
}
docontinue doesn't change values. It starts as true and you set it to true when the message is posted. On top of that you have a not in your while clause, so the loop should never run as !docontinue is always false.
Related
This question already has answers here:
How to wait for async method to complete?
(7 answers)
Closed 2 years ago.
Let's say I have a MyThread class in my Windows C# app like this:
public class MyThread
{
Thread TheThread;
public MyThread()
{
TheThread = new Thread(MyFunc);
}
public void StartIfNecessary()
{
if (!TheThread.IsAlive)
TheThread.Start();
}
private void MyFunc()
{
for (;;)
{
if (ThereIsStuffToDo)
DoSomeStuff();
}
}
}
That works fine. But now I realize I can make my thread more efficient by using async/await:
public class MyThread
{
Thread TheThread;
public MyThread()
{
TheThread = new Thread(MyFunc);
}
public void StartIfNecessary()
{
if (!TheThread.IsAlive)
TheThread.Start();
}
private async void MyFunc()
{
for (;;)
{
DoSomeStuff();
await MoreStuffIsReady();
}
}
}
What I see now, is that the second time I call StartIfNecessary(), TheThread.IsAlive is false (and ThreadState is Stopped BTW) so it calls TheThread.Start() which then throws the ThreadStateException "Thread is running or terminated; it cannot restart". But I can see that DoMoreStuff() is still getting called, so the function is in fact still executing.
I suspect what is happening, is that when my thread hits the "await", the thread I created is stopped, and when the await on MoreStuffIsReady() completes, a thread from the thread pool is assigned to execute DoSomeStuff(). So it is technically true that the thread I created has been stopped, but the function I created that thread to process is still running.
So how can I tell if "MyFunc" is still active?
I can think of 3 ways to solve this:
1) Add a "bool IsRunning" which is set to true right before calling TheThread.Start(), and MyFunc() sets to false when it completes. This is simple, but requires me to wrap everything in a try/catch/finally which isn't awful but I was hoping there was a way to have the operating system or framework help me out here just in case "MyFunc" dies in some way I wasn't expecting.
2) Find some new function somewhere in System.Threading that will give me the information I need.
3) Rethink the whole thing - since my thread only sticks around for a few milliseconds, is there a way to accomplish this same functionality without creating a thread at all (outside of the thread pool)? Start "MyFunc" as a Task somehow?
Best practices in this case?
Sticking with a Plain Old Thread and using BlockingCollection to avoid a tight loop:
class MyThread
{
private Thread worker = new Thread(MyFunc);
private BlockingCollection<Action> stuff = new BlockingCollection<Action>();
public MyThread()
{
worker.Start();
}
void MyFunc()
{
foreach (var todo in stuff.GetConsumingEnumerable())
{
try
{
todo();
}
catch(Exception ex)
{
// Something went wrong in todo()
}
}
stuff.Dispose(); // should be disposed!
}
public void Shutdown()
{
stuff.CompleteAdding(); // No more adding, but will continue to serve until empty.
}
public void Add( Action stuffTodo )
{
stuff.Add(stuffTodo); // Will throw after Shutdown is called
}
}
BlockingCollection also shows examples with Task if you prefer to go down that road.
Rethink the whole thing
This is definitely the best option. Get rid of the thread completely.
It seems like you have a "consumer" kind of scenario, and you need a consumer with a buffer of data items to work on.
One option is to use ActionBlock<T> from TPL Dataflow:
public class NeedsADifferentName
{
ActionBlock<MyDataType> _block;
public NeedsADifferentName() => _block = new ActionBlock<MyDataType>(MyFunc);
public void QueueData(MyDataType data) => _block.Post(data);
private void MyFunc(MyDataType data)
{
DoSomeStuff(data);
}
}
Alternatively, you can build your own pipeline using something like Channels.
Executing multithreaded methods make garbage. Why is that and can we prevent it?
ThreadPool.QueueUserWorkItem(callBack, state);
EDIT:
By garbage I mean objects that are created and then went out of scope. The garbage collection is very slow because of it's old version of mono. So every kb you save from the GC is a win. If you are not familiar with the unity engine, In the screenshot please see The GC column on the highlighted row. It says 0.6kb. Therefore it create 600 bytes of garbage. The callback code is not creating any garbage so this is rooted from ThreadPool.QueueUserWorkItem
EDIT 2: To elaborate further here is a more concrete example:
public class TestThread : MonoBehaviour
{
public void Update()
{
if (Time.frameCount%10 == 0)
ThreadPool.QueueUserWorkItem(DummyMethod);
}
public void DummyMethod(object meaningless)
{
}
}
Here is the result. Please look at the highlighted row. The GC column says 285Bytes. Since DummyMethod is not doing anything, the garbage is related to ThreadPool.
Edit 3:
To relax the situation and find an alternative, it would be acceptable to have a worker thread that executes jobs from a queue.
It would be OK But it MUST run on CPU other than the one unity uses if there are multiple CPUs available. Unity does nearly anything in a single thread so a background worker on the same CPU would be a disaster. Also it is a cross platform project so windows-only solutions won't work. So basically I need a worker thread solution and to know if it possible to realize if a thread's CPU is the same as another thread's.
When you ThreadPool.QueueUserWorkItem(DummyMethod); it actually is implicitly turning your code in to ThreadPool.QueueUserWorkItem(new WaitCallback(DummyMethod));, that callback may be the item that is getting put on to the GC. Try the following code to explicitly create the delegate and keep a reference to it and see if it reduces the amount of GCable data.
public class TestThread : MonoBehaviour
{
private readonly WaitCallback _callback;
public TestThread()
{
_callback = new WaitCallback(DummyMethod);
}
public void Update()
{
if (Time.frameCount%10 == 0)
ThreadPool.QueueUserWorkItem(_callback);
}
public void DummyMethod(object meaningless)
{
}
}
UPDATE: Here is a extremely basic implementation of a single threaded background worker, to give you a starting point. The below code is untested and may perform horribly, but it does give you an idea as a starting point.
public class BasicBackgroundWorker
{
private readonly Thread _backgroundWorkThread;
private readonly Queue<Action> _queue = new Queue<Action>();
private readonly ManualResetEvent _workAvailable = new ManualResetEvent(false);
public BasicBackgroundWorker()
{
_backgroundWorkThread = new Thread(BackgroundThread)
{
IsBackground = true,
Priority = ThreadPriority.BelowNormal,
Name = "BasicBackgroundWorker Thread"
};
_backgroundWorkThread.Start();
}
public void EnqueueWork(Action work)
{
lock (_queue)
{
_queue.Enqueue(work);
_workAvailable.Set();
}
}
private void BackgroundThread()
{
while (true)
{
_workAvailable.WaitOne();
Action workItem;
lock (_queue)
{
workItem = _queue.Dequeue();
if (_queue.Count == 0)
{
_workAvailable.Reset();
}
}
try
{
workItem();
}
catch (Exception ex)
{
//Log exception that happened in backgroundWork
}
}
}
}
I'm trying to optimize an async version of something similar (in basic funcionality) to the Monitor.Wait and Monitor.Pulse methods. The idea is to use this over an async method.
Requirements:
1) I have one Task running, that it is in charge of waiting until someone pulses my monitor.
2) That task may compute a complex (ie: time consuming) operation. In the meanwhile, the pulse method could be called several times without doing anything (as the main task is already doing some processing).
3) Once the main task finishes, it starts to Wait again until another Pulse comes in.
Worst case scenario is Wait>Pulse>Wait>Pulse>Wait..., but usually I have tenths/hundreds of pulses for every wait.
So, I have the following class (working, but I think it can be optimized a bit based on my requirements)
internal sealed class Awaiter
{
private readonly ConcurrentQueue<TaskCompletionSource<byte>> _waiting = new ConcurrentQueue<TaskCompletionSource<byte>>();
public void Pulse()
{
TaskCompletionSource<byte> tcs;
if (_waiting.TryDequeue(out tcs))
{
tcs.TrySetResult(1);
}
}
public Task Wait()
{
TaskCompletionSource<byte> tcs;
if (_waiting.TryPeek(out tcs))
{
return tcs.Task;
}
tcs = new TaskCompletionSource<byte>();
_waiting.Enqueue(tcs);
return tcs.Task;
}
}
The problem with the above class is the baggage I'm using just for synchronization. Since I will be waiting from one and only one thread, there is really no need to have a ConcurrentQueue, as I always have only one item in it.
So, I simplified it a bit and wrote the following:
internal sealed class Awaiter2
{
private readonly object _mutex = new object();
private TaskCompletionSource<byte> _waiting;
public void Pulse()
{
var w = _waiting;
if (w == null)
{
return;
}
lock (_mutex)
{
w = _waiting;
if (w == null)
{
return;
}
_waiting = null;
w.TrySetResult(1);
}
}
public Task Wait()
{
var w = _waiting;
if (w != null)
{
return w.Task;
}
lock (_mutex)
{
w = _waiting;
if (w != null)
{
return w.Task;
}
w = _waiting = new TaskCompletionSource<byte>();
return w.Task;
}
}
}
That new version is also working ok, but I'm still thinking it can be optimized a bit more, by removing the locks.
I'm looking for suggestions on how I can optimize the second version. Any ideas?
If you don't need the Wait() call to return a Task but are content with being able to await Wait() then you can implement a custom awaiter/awaitable.
See this link for an overview of the await pattern used by the compiler.
When implementing custom awaitables you will just be dealing with delegates and the actual "waiting" is left up to you. When you want to "await" for a condition it is often possible to keep a list of pending continuations and whenever the condition comes true you can invoke those continuations. You just need to deal with the synchronization coming from the fact that await can be called from arbitrary threads. If you know that you'll only ever await from one thread (say the UI thread) then you don't need any synchronization at all!
I'll try to give you a lock-free implementation but no guarantees that it is correct. If you don't understand why all race conditions are safe you should not use it and implement the async/await protocol using lock-statements or other techniques which you know how to debug.
public sealed class AsyncMonitor
{
private PulseAwaitable _currentWaiter;
public AsyncMonitor()
{
_currentWaiter = new PulseAwaitable();
}
public void Pulse()
{
// Optimize for the case when calling Pulse() when nobody is waiting.
//
// This has an inherent race condition when calling Pulse() and Wait()
// at the same time. The question this was written for did not specify
// how to resolve this, so it is a valid answer to tolerate either
// result and just allow the race condition.
//
if (_currentWaiter.HasWaitingContinuations)
Interlocked.Exchange(ref _currentWaiter, new PulseAwaitable()).Complete();
}
public PulseAwaitable Wait()
{
return _currentWaiter;
}
}
// This class maintains a list of waiting continuations to be executed when
// the owning AsyncMonitor is pulsed.
public sealed class PulseAwaitable : INotifyCompletion
{
// List of pending 'await' delegates.
private Action _pendingContinuations;
// Flag whether we have been pulsed. This is the primary variable
// around which we build the lock free synchronization.
private int _pulsed;
// AsyncMonitor creates instances as required.
internal PulseAwaitable()
{
}
// This check has a race condition which is tolerated.
// It is used to optimize for cases when the PulseAwaitable has no waiters.
internal bool HasWaitingContinuations
{
get { return Volatile.Read(ref _pendingContinuations) != null; }
}
// Called by the AsyncMonitor when it is pulsed.
internal void Complete()
{
// Set pulsed flag first because that is the variable around which
// we build the lock free protocol. Everything else this method does
// is free to have race conditions.
Interlocked.Exchange(ref _pulsed, 1);
// Execute pending continuations. This is free to race with calls
// of OnCompleted seeing the pulsed flag first.
Interlocked.Exchange(ref _pendingContinuations, null)?.Invoke();
}
#region Awaitable
// There is no need to separate the awaiter from the awaitable
// so we use one class to implement both parts of the protocol.
public PulseAwaitable GetAwaiter()
{
return this;
}
#endregion
#region Awaiter
public bool IsCompleted
{
// The return value of this property does not need to be up to date so we could omit the 'Volatile.Read' if we wanted to.
// What is not allowed is returning "true" even if we are not completed, but this cannot happen since we never transist back to incompleted.
get { return Volatile.Read(ref _pulsed) == 1; }
}
public void OnCompleted(Action continuation)
{
// Protected against manual invocations. The compiler-generated code never passes null so you can remove this check in release builds if you want to.
if (continuation == null)
throw new ArgumentNullException(nameof(continuation));
// Standard pattern of maintaining a lock free immutable variable: read-modify-write cycle.
// See for example here: https://blogs.msdn.microsoft.com/oldnewthing/20140516-00/?p=973
// Again the 'Volatile.Read' is not really needed since outdated values will be detected at the first iteration.
var oldContinuations = Volatile.Read(ref _pendingContinuations);
for (;;)
{
var newContinuations = (oldContinuations + continuation);
var actualContinuations = Interlocked.CompareExchange(ref _pendingContinuations, newContinuations, oldContinuations);
if (actualContinuations == oldContinuations)
break;
oldContinuations = actualContinuations;
}
// Now comes the interesting part where the actual lock free synchronization happens.
// If we are completed then somebody needs to clean up remaining continuations.
// This happens last so the first part of the method can race with pulsing us.
if (IsCompleted)
Interlocked.Exchange(ref _pendingContinuations, null)?.Invoke();
}
public void GetResult()
{
// This is just to check against manual calls. The compiler will never call this when IsCompleted is false.
// (Assuming your OnCompleted implementation is bug-free and you don't execute continuations before IsCompleted becomes true.)
if (!IsCompleted)
throw new NotSupportedException("Synchronous waits are not supported. Use 'await' or OnCompleted to wait asynchronously");
}
#endregion
}
You usually don't bother on which thread the continuations run because if they are async methods the compiler has already inserted code (in the continuation) to switch back to the right thread, no need to do it manually in every awaitable implementation.
[edit]
As a starting point for how a locking implementation can look I'll provide one using a lock-statement. It should be easy to replace it by a spinlock or some other locking technique. By using a struct as the awaitable it even has the advantage that it does no additional allocation except for the initial object. (There are of course allocations in the async/await framework in the compiler magic on the calling side, but you can't get rid of these.)
Note that the iteration counter will increment only for every Wait+Pulse pair and will eventually overflow into negative, but that is ok. We just need to bridge the time from the continuation beeing invoked until it can call GetResult. 4 billion Wait+Pulse pairs should be plenty of time for any pending continuations to call its GetResult method. If you don't want that risk you could use a long or Guid for a more unique iteration counter, but IMHO an int is good for almost all scenarios.
public sealed class AsyncMonitor
{
public struct Awaitable : INotifyCompletion
{
// We use a struct to avoid allocations. Note that this means the compiler will copy
// the struct around in the calling code when doing 'await', so for your own debugging
// sanity make all variables readonly.
private readonly AsyncMonitor _monitor;
private readonly int _iteration;
public Awaitable(AsyncMonitor monitor)
{
lock (monitor)
{
_monitor = monitor;
_iteration = monitor._iteration;
}
}
public Awaitable GetAwaiter()
{
return this;
}
public bool IsCompleted
{
get
{
// We use the iteration counter as an indicator when we should be complete.
lock (_monitor)
{
return _monitor._iteration != _iteration;
}
}
}
public void OnCompleted(Action continuation)
{
// The compiler never passes null, but someone may call it manually.
if (continuation == null)
throw new ArgumentNullException(nameof(continuation));
lock (_monitor)
{
// Not calling IsCompleted since we already have a lock.
if (_monitor._iteration == _iteration)
{
_monitor._waiting += continuation;
// null the continuation to indicate the following code
// that we completed and don't want it executed.
continuation = null;
}
}
// If we were already completed then we didn't null the continuation.
// (We should invoke the continuation outside of the lock because it
// may want to Wait/Pulse again and we want to avoid reentrancy issues.)
continuation?.Invoke();
}
public void GetResult()
{
lock (_monitor)
{
// Not calling IsCompleted since we already have a lock.
if (_monitor._iteration == _iteration)
throw new NotSupportedException("Synchronous wait is not supported. Use await or OnCompleted.");
}
}
}
private Action _waiting;
private int _iteration;
public AsyncMonitor()
{
}
public void Pulse(bool executeAsync)
{
Action execute = null;
lock (this)
{
// If nobody is waiting we don't need to increment the iteration counter.
if (_waiting != null)
{
_iteration++;
execute = _waiting;
_waiting = null;
}
}
// Important: execute the callbacks outside the lock because they might Pulse or Wait again.
if (execute != null)
{
// If the caller doesn't want inlined execution (maybe he holds a lock)
// then execute it on the thread pool.
if (executeAsync)
Task.Run(execute);
else
execute();
}
}
public Awaitable Wait()
{
return new Awaitable(this);
}
}
Here is my simple async implementation that I use in my projects:
internal sealed class Pulsar
{
private static TaskCompletionSource<bool> Init() => new TaskCompletionSource<bool>();
private TaskCompletionSource<bool> _tcs = Init();
public void Pulse()
{
Interlocked.Exchange(ref _tcs, Init()).SetResult(true);
}
public Task AwaitPulse(CancellationToken token)
{
return token.CanBeCanceled ? _tcs.Task.WithCancellation(token) : _tcs.Task;
}
}
Add TaskCreationOptions.RunContinuationsAsynchronously to the TCS for async continuations.
The WithCancellation can be omitted of course, if you do not need cancellations.
Because you only have one task ever waiting your function can be simplified to
internal sealed class Awaiter3
{
private volatile TaskCompletionSource<byte> _waiting;
public void Pulse()
{
var w = _waiting;
if (w == null)
{
return;
}
_waiting = null;
#if NET_46_OR_GREATER
w.TrySetResult(1);
#else
Task.Run(() => w.TrySetResult(1));
#endif
}
//This method is not thread safe and can only be called by one thread at a time.
// To make it thread safe put a lock around the null check and the assignment,
// you do not need to have a lock on Pulse, "volatile" takes care of that side.
public Task Wait()
{
if(_waiting != null)
throw new InvalidOperationException("Only one waiter is allowed to exist at a time!");
#if NET_46_OR_GREATER
_waiting = new TaskCompletionSource<byte>(TaskCreationOptions.RunContinuationsAsynchronously);
#else
_waiting = new TaskCompletionSource<byte>();
#endif
return _waiting.Task;
}
}
One behavior I did change. If you are using .NET 4.6 or newer use the code in the #if NET_46_OR_GREATER blocks, if under use the else blocks. When you call TrySetResult you could have the continuation synchronously run, this can cause Pulse() to take a long time to complete. By using TaskCreationOptions.RunContinuationsAsynchronously in .NET 4.6 or wrapping the TrySetResult in a Task.Run for pre 4.6 will make sure that Puse() is not blocked by the continuation of the task.
See the SO question Detect target framework version at compile time on how to make a NET_46_OR_GREATER definition that works in your code.
A simple way to do this is to use SemaphoreSlim which uses Monitor.
public class AsyncMonitor
{
private readonly SemaphoreSlim signal = new SemaphoreSlim(0, 1);
public void Pulse()
{
try
{
signal.Release();
}
catch (SemaphoreFullException) { }
}
public async Task WaitAsync(CancellationToken cancellationToken)
{
await signal.WaitAsync(cancellationToken).ConfigureAwait(false);
}
}
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);
}
}
}
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