Lock around dictionary access in a WPF application - c#

I'm working on an old and large WPF application. The customer reported a bug, which they were able to reproduce, but I can't. There is a class in the application that looks like this:
public static class PermissionProvider
{
private static Dictionary<string, bool> Permissions;
public static void Init()
{
Permissions = new Dictionary<string, bool>();
}
private static object _lock = new object();
public static bool HasPermission(string permission)
{
if (string.IsNullOrEmpty(permission)) return false;
lock (_lock)
{
if (Permissions.ContainsKey(permission)) return Permissions[permission];
var hasPermission = true; // Expensive call a third party module to check user permissions.
Permissions.Add(permission, hasPermission);
return hasPermission;
}
}
}
According to the log files provided by the customer, the line Permissions.Add(permission, hasPermission) threw an ArgumentException (key already exists). This doesn't make sense to me; the code checks for the key inside the same lock.
Based on a test run, all calls to HasPermission seem to be made from the main thread. The program uses Dispatcher.BeginInvoke at places, but my understanding is that locking is not even necessary for that. The dictionary is private and not accessed from anywhere else.
In what situation could this exception happen?
My first thought was that the customer was running an old version of the application, but it turns out that this class was only added in the latest one.
This particular exception should be easy enough to avoid by just changing the Permissions.Add(permission, hasPermission) to Permissions[permission] = hasPermission, but I would prefer to understand why it happened first.

It is possible, but hard to tell without the whole source code.
The expensive call
var hasPermission = true; // Expensive call a third party module to check user permissions.
could do something that calls HasPermission() again. Thus, the same thread would enter
lock (_lock) { ... }
again (which is allowed), possibly adding the the permissing, leaving the lock, leaving the method and returning into HasPermission() where it came from, adding the same key again.
This might either require production debugging at your customer. If you're not familiar with that and you can convince your customer to replace the affected DLL for a moment (let him create a backup copy), you could try the following:
lock (_lock)
{
var stack = Environment.StackTrace;
if (stack.Split(new []{nameof(HasPermission)}, StringSplitOptions.None).Length> 2) throw new Exception("I should not be in here twice");
...
}
This should crash the application (unless general catch block somewhere) with a call stack that has the affected method twice, thus you can analyze where the second call comes from. Do whatever you would do in such a case: generate a crash dump, analyze your logs, ...
Generating a stack trace is considerably expensive, so this will change timing and thus potentially make the problem disappear. A disappeared problem is not a fixed problem, though.

I agree with Thomas Weller that the most likely reason is that the same thread reenter the lock for some reason. But i wanted to suggest another approach to these kinds of problems.
Holding a lock while calling arbitrary code can be dangerous, it may lead to deadlocks and various other issues. To limit such risks it is a good idea to only hold locks for short sections of code, only call code you know is safe, and does not raise events or can run arbitrary code some other way.
One option would be to switch to a 'publication only' model for thread safety that releases the lock while calling the 'expensive method'. This might allow multiple threads to call the expensive method at the same time, and this might or might not be an issue in your particular case. Something like:
lock (_lock)
{
if (Permissions.ContainsKey(permission)) return Permissions[permission];
}
var hasPermission = true; // Expensive call a third party module to check user permissions.
lock (_lock)
{
if (Permissions.ContainsKey(permission)) return Permissions[permission];
Permissions.Add(permission, hasPermission);
return hasPermission;
}
Or use ConcurrentDictionary.GetOrAdd that does more or less the same thing.
I would also caution against mutable global state in general since this can also make code hard to read and predict.

As pointed out by JonasH in a comment, the Init method looks highly suspicious. Your program could crash if this method is not called exactly once. If you are not sure how many times it's called, at least protect the code it contains with the same lock.
public static void Init()
{
lock (_lock)
{
Permissions = new Dictionary<string, bool>();
}
}

Related

C# lock based on class property

I've seen many examples of the lock usage, and it's usually something like this:
private static readonly object obj = new object();
lock (obj)
{
// code here
}
Is it possible to lock based on a property of a class? I didn't want to lock globally for any calls to the method with the lock statement, I'd like to lock only if the object passed as argument had the same property value as another object which was being processed prior to that.
Is that possible? Does that make sense at all?
This is what I had in mind:
public class GmailController : Controller
{
private static readonly ConcurrentQueue<PushRequest> queue = new ConcurrentQueue<PushRequest>();
[HttpPost]
public IActionResult ProcessPushNotification(PushRequest push)
{
var existingPush = queue.FirstOrDefault(q => q.Matches(push));
if (existingPush == null)
{
queue.Enqueue(push);
existingPush = push;
}
try
{
// lock if there is an existing push in the
// queue that matches the requested one
lock (existingPush)
{
// process the push notification
}
}
finally
{
queue.TryDequeue(out existingPush);
}
}
}
Background: I have an API where I receive push notifications from Gmail's API when our users send/receive emails. However, if someone sends a message to two users at the same time, I get two push notifications. My first idea was querying the database before inserting (based on subject, sender, etc). In some rare cases, the query of the second call is made before the SaveChanges of the previous call, so I end up having duplicates.
I know that if I ever wanted to scale out, lock would become useless. I also know I could just create a job to check recent entries and eliminate duplicates, but I was trying something different. Any suggestions are welcome.
Let me first make sure I understand the proposal. The problem given is that we have some resource shared to multiple threads, call it database, and it admits two operations: Read(Context) and Write(Context). The proposal is to have lock granularity based on a property of the context. That is:
void MyRead(Context c)
{
lock(c.P) { database.Read(c); }
}
void MyWrite(Context c)
{
lock(c.P) { database.Write(c); }
}
So now if we have a call to MyRead where the context property has value X, and a call to MyWrite where the context property has value Y, and the two calls are racing on two different threads, they are not serialized. However, if we have, say, two calls to MyWrite and a call to MyRead, and in all of them the context property has value Z, those calls are serialized.
Is this possible? Yes. That doesn't make it a good idea. As implemented above, this is a bad idea and you shouldn't do it.
It is instructive to learn why it is a bad idea.
First, this simply fails if the property is a value type, like an integer. You might think, well, my context is an ID number, that's an integer, and I want to serialize all accesses to the database using ID number 123, and serialize all accesses using ID number 345, but not serialize those accesses with respect to each other. Locks only work on reference types, and boxing a value type always gives you a freshly allocated box, so the lock would never be contested even if the ids were the same. It would be completely broken.
Second, it fails badly if the property is a string. Locks are logically "compared" by reference, not by value. With boxed integers, you always get different references. With strings, you sometimes get different references! (Because of interning being applied inconsistently.) You could be in a situation where you are locking on "ABC" and sometimes another lock on "ABC" waits, and sometimes it does not!
But the fundamental rule that is broken is: you must never lock on an object unless that object has been specifically designed to be a lock object, and the same code which controls access to the locked resource controls access to the lock object.
The problem here is not "local" to the lock but rather global. Suppose your property is a Frob where Frob is a reference type. You don't know if any other code in your process is also locking on that same Frob, and therefore you don't know what lock ordering constraints are necessary to prevent deadlocks. Whether a program deadlocks or not is a global property of a program. Just like you can build a hollow house out of solid bricks, you can build a deadlocking program out of a collection of locks that are individually correct. By ensuring that every lock is only taken out on a private object that you control, you ensure that no one else is ever locking on one of your objects, and therefore the analysis of whether your program contains a deadlock becomes simpler.
Note that I said "simpler" and not "simple". It reduces it to almost impossible to get correct, from literally impossible to get correct.
So if you were hell bent on doing this, what would be the right way to do it?
The right way would be to implement a new service: a lock object provider. LockProvider<T> needs to be able to hash and compare for equality two Ts. The service it provides is: you tell it that you want a lock object for a particular value of T, and it gives you back the canonical lock object for that T. When you're done, you say you're done. The provider keeps a reference count of how many times it has handed out a lock object and how many times it got it back, and deletes it from its dictionary when the count goes to zero, so that we don't have a memory leak.
Obviously the lock provider needs to be threadsafe and needs to be extremely low contention, because it is a mechanism designed to prevent contention, so it had better not cause any! If this is the road you intend to go down, you need to get an expert on C# threading to design and implement this object. It is very easy to get this wrong. As I have noted in comments to your post, you are attempting to use a concurrent queue as a sort of poor lock provider and it is a mass of race condition bugs.
This is some of the hardest code to get correct in all of .NET programming. I have been a .NET programmer for almost 20 years and implemented parts of the compiler and I do not consider myself competent to get this stuff right. Seek the help of an actual expert.
Although I find Eric Lippert's answer fantastic and marked it as the correct one (and I won't change that), his thoughts made me think and I wanted to share an alternative solution I found to this problem (and I'd appreciate any feedbacks), even though I'm not going to use it as I ended up using Azure functions with my code (so this wouldn't make sense), and a cron job to detected and eliminate possible duplicates.
public class UserScopeLocker : IDisposable
{
private static readonly object _obj = new object();
private static ICollection<string> UserQueue = new HashSet<string>();
private readonly string _userId;
protected UserScopeLocker(string userId)
{
this._userId = userId;
}
public static UserScopeLocker Acquire(string userId)
{
while (true)
{
lock (_obj)
{
if (UserQueue.Contains(userId))
{
continue;
}
UserQueue.Add(userId);
return new UserScopeLocker(userId);
}
}
}
public void Dispose()
{
lock (_obj)
{
UserQueue.Remove(this._userId);
}
}
}
...then you would use it like this:
[HttpPost]
public IActionResult ProcessPushNotification(PushRequest push)
{
using(var scope = UserScopeLocker.Acquire(push.UserId))
{
// process the push notification
// two threads can't enter here for the same UserId
// the second one will be blocked until the first disposes
}
}
The idea is:
UserScopeLocker has a protected constructor, ensuring you call Acquire.
_obj is private static readonly, only the UserScopeLocker can lock this object.
_userId is a private readonly field, ensuring even its own class can't change its value.
lock is done when checking, adding and removing, so two threads can't compete on these actions.
Possible flaws I detected:
Since UserScopeLocker relies on IDisposable to release some UserId, I can't guarantee the caller will properly use using statement (or manually dispose the scope object).
I can't guarantee the scope won't be used in a recursive function (thus possibly causing a deadlock).
I can't guarantee the code inside the using statement won't call another function which also tries to acquire a scope to the user (this would also cause a deadlock).

new instance of Object()

I came across this definition of Object constructor (metadata from mscorlib.dll)
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public Object();
I didn't understood what ConstrainedExecution (Cer.MayFail) mean can someone tell me with an example in this case.
I came across this code, also tell me if it is correct to write like this,
public class MyClass
{
private static object instanceLock = new object();
private void Func()
{
bool instanceLockTaken = false;
Monitor.TryEnter(instanceLock, ref instanceLockTaken);
//...
Monitor.Exit(instanceLock);
}
}
Constrained Execution is what you're trying to achieve by locking the thread.
From: http://msdn.microsoft.com/en-us/magazine/cc163716.aspx
A Cer value of MayFail is used to signal that when faced with
asynchronous exceptions, the code may not complete in an expected
fashion. Since thread aborts are being delayed over constrained
execution regions, this really means that your code is doing something
that may cause memory to be allocated or that might result in a stack
overflow. More importantly, it means that you must take the possible
failures into consideration when calling this method.
In your case, because the object is static and only created once, this will not be a problem.
Monitor.TryEnter returns immediately even if a lock was not acquired. It has a boolean value, which you're not checking, something like this would work:
Monitor.TryEnter(instanceLock, ref instanceLockTaken);
if (instanceLockTaken)
{
// Do stuff here
Monitor.Exit(instanceLock);
}
However, this code would mean that the if {} block would not be executed every time, if you want to acquire a lock on every thread, you'll need to do something like this:
lock(instanceLock)
{
// Do stuff here
}
This means that only a single thread can run the contents of the lock {} statement at a time, and the contents of the lock statement will be executed every time.
On a side note, you can also make the object you're locking readonly:
private static readonly object instanceLock = new object();
So, generally speaking, you have 2 questions here.
1) Reliability contracts is a tool used by CLR team to support constrained execution regions. It is an advanced topic, but simply speaking the construction describes if a function (or a constructor) can fail, and if yes, what impact will be ( no impact, appDomain impact, process impact, whole machine crush, etc)
2) Your code snippet is incorrect. Why do you saving instanceLockTaken if you are not going to check it further? Furthermore, if exception occur between the lock acquisition and releasing it, you'll leak the lock.
Consider using the lock statement, which is syntax sugar for something like this:
bool instanceLockTaken = false;
try
{
Monitor.Enter(instanceLock, ref instanceLockTaken);
//...
}
finally
{
if (instanceLockTaken)
{
Monitor.Exit(instanceLock);
}
}
Cer.Mayfail keyword implies that if the marked method throws an exception, the data may be in an invalid state; the previous state of the object will not be restored.
This is the correct way for Monitor locking;
bool isLocked = false;
try
{
Monitor.Enter(instanceLock , ref isLocked);
// Do some things within the lock
}
finally
{
if (isLocked) Monitor.Exit(instanceLock);
}
As for cer.mayfail this link will provide some more information http://weblogs.asp.net/justin_rogers/archive/2004/10/05/238275.aspx

locking only when modifying vs entire method

When should locks be used? Only when modifying data or when accessing it as well?
public class Test {
static Dictionary<string, object> someList = new Dictionary<string, object>();
static object syncLock = new object();
public static object GetValue(string name) {
if (someList.ContainsKey(name)) {
return someList[name];
} else {
lock(syncLock) {
object someValue = GetValueFromSomeWhere(name);
someList.Add(name, someValue);
}
}
}
}
Should there be a lock around the the entire block or is it ok to just add it to the actual modification? My understanding is that there still could be some race condition where one call might not have found it and started to add it while another call right after might have also run into the same situation - but I'm not sure. Locking is still so confusing. I haven't run into any issues with the above similar code but I could just be lucky so far. Any help above would be appriciated as well as any good resources for how/when to lock objects.
You have to lock when reading too, or you can get unreliable data, or even an exception if a concurrent modification physically changes the target data structure.
In the case above, you need to make sure that multiple threads don't try to add the value at the same time, so you need at least a read lock while checking whether it is already present. Otherwise multiple threads could decide to add, find the value is not present (since this check is not locked), and then all try to add in turn (after getting the lock)
You could use a ReaderWriterLockSlim if you have many reads and only a few writes. In the code above you would acquire the read lock to do the check and upgrade to a write lock once you decide you need to add it. In most cases, only a read lock (which allows your reader threads to still run in parallel) would be needed.
There is a summary of the available .Net 4 locking primitives here. Definitely you should understand this before you get too deep into multithreaded code. Picking the correct locking mechanism can make a huge performance difference.
You are correct that you have been lucky so far - that's a frequent feature of concurrency bugs. They are often hard to reproduce without targeted load testing, meaning correct design (and exhaustive testing, of course) is vital to avoid embarrassing and confusing production bugs.
Lock the whole block before you check for the existence of name. Otherwise, in theory, another thread could add it between the check, and your code that adds it.
Actually locking just when you perform the Add really doesn't do anything at all. All that would do is prevent another thread from adding something simultaneously. But since that other thread would have already decided it was going to do the add, it would just try to do it anyway as soon as the lock was released.
If a resource can only be accessed by multiple threads, you do not need any locks.
If a resource can be accessed by multiple threads and can be modified, then all accesses/modifications need to be synchronized. In your example, if GetValueFromSomeWhere takes a long time to return, it is possible for a second call to be made with the same value in name, but the value has not been stored in the Dictionary.
ReaderWriterLock or the slim version if you under 4.0.
You will aquire the reader lock for the reads (will allow for concurrent reads) and upgrade the lock to the writer lock when something is to write (will allow only one write at the time and will block all the reads until is done, as well as the concurrent write-threads).
Make sure to release your locks with the pattern to avoid deadlocking:
void Write(object[] args)
{
this.ReaderWriterLock.AquireWriteLock(TimeOut.Infinite);
try
{
this.myData.Write(args);
}
catch(Exception ex)
{
}
finally
{
this.ReaderWriterLock.RelaseWriterLock();
}
}

ReaderWriterLockSection: A bad idea?

In writing some threaded code, I've been using the ReaderWriterLockSlim class to handle synchronized access to variables. Doing this, I noticed I was always writing try-finally blocks, the same for each method and property.
Seeing an opportunity to avoid repeating myself and encapsulate this behaviour I built a class, ReaderWriterLockSection, intended to be used as a thin wrapper to the lock which can be used with the C# using block syntax.
The class is mostly as follows:
public enum ReaderWriterLockType
{
Read,
UpgradeableRead,
Write
}
public class ReaderWriterLockSection : IDisposeable
{
public ReaderWriterLockSection(
ReaderWriterLockSlim lock,
ReaderWriterLockType lockType)
{
// Enter lock.
}
public void UpgradeToWriteLock()
{
// Check lock can be upgraded.
// Enter write lock.
}
public void Dispose()
{
// Exit lock.
}
}
I use the section as follows:
private ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
public void Foo()
{
using(new ReaderWriterLockSection(_lock, ReaderWriterLockType.Read)
{
// Do some reads.
}
}
To me, this seems like a good idea, one that makes my code easier to read and seemingly more robust since I wont ever forget to release a lock.
Can anybody see an issue with this approach? Is there any reason this is a bad idea?
Well, it seems okay to me. Eric Lippert has previously written about the dangers of using Dispose for "non-resource" scenarios, but I think this would count as a resource.
It may make life tricky in upgrade scenarios, but you could always fall back to a more manual bit of code at that point.
Another alternative is to write a single lock acquire/use/release method and provide the action to take while holding the lock as a delegate.
I usually indulge into this kind of code-sugary confections!
Here's a variant that's a bit easier to read for the users, on top of your API
public static class ReaderWriterLockExt{
public static IDisposable ForRead(ReaderWriterLockSlim rwLock){
return new ReaderWriterLockSection(rwLock,ReaderWriterLockType.Read);
}
public static IDisposable ForWrite(ReaderWriterLockSlim rwLock){
return new ReaderWriterLockSection(rwLock,ReaderWriterLockType.Write);
}
public static IDisposable ForUpgradeableRead(ReaderWriterLockSlim wrLock){
return new ReaderWriterLockSection(rwLock,ReaderWriterLockType.UpgradeableRead);
}
}
public static class Foo(){
private static readonly ReaderWriterLockSlim l=new ReaderWriterLockSlim(); // our lock
public static void Demo(){
using(l.ForUpgradeableRead()){ // we might need to write..
if(CacheExpires()){ // checks the scenario where we need to write
using(l.ForWrite()){ // will request the write permission
RefreshCache();
} // relinquish the upgraded write
}
// back into read mode
return CachedValue();
} // release the read
}
}
I also recommend using a variant that takes an Action delegate that's invoked when the lock cannot be obtained for 10 seconds, which I'll leave as an exercise to the reader.
You might also want to check for a null RWL in the static extension methods, and make sure the lock exists when you dispose it.
Cheers,
Florian
There is another consideration here, you are possibly solving a problem you should not solve. I can't see the rest of your code but I can guess from you seeing value in this pattern.
Your approach solves a problem only if the code that reads or writes the shared resource throws an exception. Implicit is that you don't handle the exception in the method that does the reading/writing. If you did, you could simply release the lock in the exception handling code. If you don't handle the exception at all, the thread will die from the unhandled exception and your program will terminate. No point in releasing a lock then.
So there's a catch clause somewhere lower in the call stack that catches the exception and handles it. This code has to restore the state of the program so that it can meaningful continue without generating bad data or otherwise die due to exceptions caused by altered state. That code has a difficult job to do. It needs to somehow guess how much data was read or written without having any context. Getting it wrong, or only partly right, is potentially very destabilizing to the entire program. After all, it was a shared resource, other threads are reading/writing from it.
If you know how to do this, then by all means use this pattern. You better test the heck out of though. If you're not sure then avoid wasting system resources on a problem you can't reliably fix.
One thing I'd suggest when wrapping a lock to facilitate the "using" pattern is to include a "danger-state" field in the lock; before allowing any code to enter the lock, the code should check the danger state. If the danger state is set, and the code which is trying to enter the lock hasn't passed a special parameter saying it's expecting that it might be, the attempt to acquire the lock should throw an exception. Code which is going to temporarily put the guarded resource into a bad state should set the danger state flag, do what needs to be done, and then reset the danger state flag once the operation is complete and the object is in a safe state.
If an exception occurs while the danger state flag is set, the lock should be released but the danger state flag should remain set. This will ensure that code which wants to access the resource will find out that the resource is corrupted, rather than waiting forever for the lock to be released (which would be the outcome if there were no "using" or "try-finally" block).
If the lock being wrapped is a ReaderWriterLock, it may be convenient to have the acquisition of a "writer" lock automatically set the danger state; unfortunately, there's no way for an IDisposable used by a using block to determine whether the block is being exited cleanly or via exception. Consequently, I don't know any way to use something syntactically like a 'using' block to guard the "danger state" flag.

How to make a method exclusive in a multithreaded context?

I have a method which should be executed in an exclusive fashion. Basically, it's a multi threaded application where the method is invoked periodically by a timer, but which could also be manually triggered by a user action.
Let's take an example :
The timer elapses, so the method is
called. The task could take a few
seconds.
Right after, the user clicks on some
button, which should trigger the
same task : BAM. It does nothing
since the method is already running.
I used the following solution :
public void DoRecurentJob()
{
if(!Monitor.TryEnter(this.lockObject))
{
return;
}
try
{
// Do work
}
finally
{
Monitor.Exit(this.lockObject);
}
}
Where lockObject is declared like that:
private readonly object lockObject = new object();
Edit : There will be only one instance of the object which holds this method, so I updated the lock object to be non-static.
Is there a better way to do that ? Or maybe this one is just wrong for any reason ?
This looks reasonable if you are just interested in not having the method run in parallel. There's nothing to stop it from running immediately after each other, say that you pushed the button half a microsecond after the timer executed the Monitor.Exit().
And having the lock object as readonly static also make sense.
You could also use Mutex or Semaphore if you want it to work cross process (with a slight performance penalty), or if you need to set any other number than one of allowed simultaneous threads running your piece of code.
There are other signalling constructs that would work, but your example looks like it does the trick, and in a simple and straightforward manner.
Minor nit: if the lockObject variable is static, then "this.lockObject" shouldn't compile. It also feels slightly odd (and should at least be heavily documented) that although this is an instance method, it has distinctly type-wide behaviour as well. Possibly make it a static method which takes an instance as the parameter?
Does it actually use the instance data? If not, make it static. If it does, you should at least return a boolean to say whether or not you did the work with the instance - I find it hard to imagine a situation where I want some work done with a particular piece of data, but I don't care if that work isn't performed because some similar work was being performed with a different piece of data.
I think it should work, but it does feel a little odd. I'm not generally a fan of using manual locking, just because it's so easy to get wrong - but this does look okay. (You need to consider asynchronous exceptions between the "if" and the "try" but I suspect they won't be a problem - I can't remember the exact guarantees made by the CLR.)
I think Microsoft recommends using the lock statement, instead of using the Monitor class directly. It gives a cleaner layout and ensures the lock is released in all circumstances.
public class MyClass
{
// Used as a lock context
private readonly object myLock = new object();
public void DoSomeWork()
{
lock (myLock)
{
// Critical code section
}
}
}
If your application requires the lock to span all instances of MyClass you can define the lock context as a static field:
private static readonly object myLock = new object();
The code is fine, but would agree with changing the method to be static as it conveys intention better. It feels odd that all instances of a class have a method between them that runs synchronously, yet that method isn't static.
Remember you can always have the static syncronous method to be protected or private, leaving it visible only to the instances of the class.
public class MyClass
{
public void AccessResource()
{
OneAtATime(this);
}
private static void OneAtATime(MyClass instance)
{
if( !Monitor.TryEnter(lockObject) )
// ...
This is a good solution although I'm not really happy with the static lock. Right now you're not waiting for the lock so you won't get into trouble with deadlocks. But making locks too visible can easily get you in to trouble the next time you have to edit this code. Also this isn't a very scalable solution.
I usually try to make all the resources I try to protect from being accessed by multiple threads private instance variables of a class and then have a lock as a private instance variable too. That way you can instantiate multiple objects if you need to scale.
A more declarative way of doing this is using the MethodImplOptions.Synchronized specifier on the method to which you wish to synchronize access:
[MethodImpl(MethodImplOptions.Synchronized)]
public void OneAtATime() { }
However, this method is discouraged for several reasons, most of which can be found here and here. I'm posting this so you won't feel tempted to use it. In Java, synchronized is a keyword, so it may come up when reviewing threading patterns.
We have a similar requirement, with the added requirement that if the long-running process is requested again, it should enqueue to perform another cycle after the current cycle is complete. It's similar to this:
https://codereview.stackexchange.com/questions/16150/singleton-task-running-using-tasks-await-peer-review-challenge
private queued = false;
private running = false;
private object thislock = new object();
void Enqueue() {
queued = true;
while (Dequeue()) {
try {
// do work
} finally {
running = false;
}
}
}
bool Dequeue() {
lock (thislock) {
if (running || !queued) {
return false;
}
else
{
queued = false;
running = true;
return true;
}
}
}

Categories