My app saves data to a file - I obviously don't want the app to write to the file from multiple locations on disk. What I want is a generic "utility" class that will know how to run a piece of code (let's call it SingletonTask) with the following rules:

1. Only one SingletonTask will run at any given moment in the system - EDIT: note that this singleton task may be asynchronous in nature and may require execution on the UI thread.
2. When multiple calls are made to run the SingletonTask, the first one will immediately run the SingletonTask and every subsequent call that happens before SingletonTask runs will "queue up".
3. All calls that are "queued up" during the run of SingletonTask will cause only a single new SingletonTask to execute (and all of them will complete when that one SingletonTask completes)
4. Obviously, if during the SingletonTask executed in (3), more calls come in, they will follow rule (2) and so on.

I could not find anything like this in .NET (looking for something that works on Win8) - but maybe I don't know what the correct keywords are.

In any case - here's my attempt at doing this.. I have a utility class called SigletonTask you inherit from. That class has a protected abstract method called RunProcessAsync(). The method users call is RunAsync() and it behaves as described in the above rules.

I tested this and it seems to work, however, there is an issue with it: It's currently limiting usage to from within the UI thread. This makes the solution simpler, but means you cannot use it from arbitrary threads. I looked into locking inside the method, but could not come up with something elegant that does not deadlock.

My questions are:

1. Can you see any issues with the code?
2. Can you make the code better?

(EDIT: This is a new version. Old version at the bottom.)

(Also - it's based on cold tasks)

public abstract class SingletonTask
{
private object m_lock = new object();

{
}

{
return RunAsync(() => RunProcessAsync());
}

{
lock (m_lock)
{
{
}
else
{

{
}

}
}

if (start1 != null)
{
start1.Start().RunWithoutWarning();
}

{
}

if (start2 != null)
{
start2.Start().RunWithoutWarning();
}

{
}

}

{
return null;
}
}


And here's how you inherit from it:

class MySing : SingletonTask
{
private int m_id = 1000;
Action<string> log;
public MySing(Action<string> log, CoreDispatcher dispatcher) : base(dispatcher)
{
this.log = log;
}
{
int id = m_id++;
log("Before delay for " + id.ToString());
log("After delay for " + id.ToString());
}
}


My test app is fairly simple - there's a button that calls into an instance of MySing and awaits the result, logging before awaiting and after awaiting:

private void Button_Click_1(object sender, RoutedEventArgs e)
{
int id = m_id++;
Log("Running with id=" + id.ToString());
await m_sing.RunAsync();
Log("Run returned with id=" + id.ToString());
}


Tap the button 3 times quickly, for example, and you should see:

Running with id=0

Before delay for 1000

runnjng with id=1

Running with id=2

After delay for 1000

Run returned with id=0

Before delay for 1001

After delay for 1001

Run returned with id=1

Run returned with id=2

(I hope asking such a question is kosher here)

------------------------- OLD -------------------------------

(This is the code for my original question, before the edit.)

public abstract class SingletonTask
{

private object m_lock = new object();
private CoreDispatcher m_dispatcher = null;

{
m_dispatcher = dispatcher;
}

{
{
}

{
firstRun = innerRun;
}
{
{
}

}

if (firstRun != null)
{
await firstRun;
}
}

}

• Found anything neater? – Şafak Gür Oct 18 '12 at 13:58
• Updated. I think I found something I am happy with. Had to implement Cold tasks for it (link just above the new code). This seems to work great and works from any thread. – Shahar Prish Oct 18 '12 at 14:13

I made something like this before but I don't claim that it's better.
Although it's much simpler:

public sealed class SingleTask
{
private readonly object _Lock = new object();

{
lock (_Lock)
}
{
lock (_Lock)
{
}
}
}


You can use ContinueWith methods for queuing actions so I don't think you need a custom approach here. Here the Queue methods also return task objects so you can wait them individually.

You can make this class static if you want it to behave like a singleton.
But I can't see a reason for doing so.

As for your code, I don't see any issues with it.

Edit (Usage)

Let's say you have these methods you want to run asynchronously:

private void LongInitialization() { /* Some operation */ }
private int LongCalculation() { /* Some operation */ }


You can:

// Creates a completed task.

// Starts initialization and returns its task.

// Queues LongCalculation to run after LongInitialization is completed.


In these samples however, you can't interact with UI controls because you can't access a control from a thread other than the one the control was created on. So if you have a method like this:

private void UpdateText() { txtStatus.Text = GetStatusFromDB(); }


...which interacts with a TextBox, and if you call single.Queue(UpdateText), you'll see an exception is thrown with the message: "Cross-thread operation not valid".

What you can do here to prevent this, is providing an overload to the SingleTask's Queue(Action) method that takes a TaskScheduler as a parameter:

public Task Queue(Action action, TaskScheduler scheduler)
{
lock (_Lock)
}


Then you can call it like this:

single.Queue(UpdateText, TaskScheduler.FromCurrentSynchronizationContext());


By calling Queue like this on a UI thread you say "Hey! Here is the UI's synchronization context, call its Post method so it won't break my program".

You also can provide overloads to Queue so it can take TaskContinuationOptions (if you want to specify LongRunning and make it run on a different thread, etc.) and/or CancellationToken parameters (if you want to provide cancellation). For example:

public Task Queue(Action<CancellationToken> action,
CancellationToken token)
{
lock (_Lock)
.ContinueWith(t => action.Invoke(token), token, options, scheduler);
}


You can share the same SingleTask insance anywhere you want to do things asynchronously but in an order so, I hope this will satisfy your goals. Again, if you want to have only one instance of this, you can always make this class static.

• So in this solution dead locking could occur if somebody were to await on the returned Task forever, though a bug, still a realistic scenario right? – Mike Perrenoud Oct 3 '12 at 12:07
• Hey! Thanks for the reply. So - the issue I am seeing here is that your functions are not async themselves - you are going to run them on a separate thread but if, say, they need the UI thread, or if your task is simply of an asynchronous nature you need to wrap it in a Func<> or Action and do .Wait() on it right? Updated my original question. – Shahar Prish Oct 3 '12 at 19:09
• @ŞafakGür That's great - but again - what I meant is that the action you are scheduling is not async by itself. You could, for example, in the action, type the following: () => DoSomethingAsync.Wait(), however, that means you have a whole thread that's "taken" waiting for the operation to complete. I want the action you execute itself to be Asynchronous - not the method that executes the action. Note how in my implementation, RunProcessAsync() is itself an async operation). – Shahar Prish Oct 4 '12 at 7:43
• @Shahar: So you want to queue operations that are already asynchronous I guess? Alright then, let me look that again :) – Şafak Gür Oct 4 '12 at 7:49
• @Shahar: I see your point; async/await thingy already does it by sending the rest of the method as a delegate to the awaitable to invoke when its job is done and provide synchronization to asynchronous operations. I don't think I can add much to your wrapper in this case. You may want to change m_id++ to Interlocked.Increment(ref m_id) but other than that, your approach seems solid enough to me. I may need something like this, too so I'll look more into it when I can. Hope you'll end up with something neater. – Şafak Gür Oct 4 '12 at 8:33

Okay, after much updating I effectively have two approaches. Both of them use a Queue, but one uses the new ConcurrentQueue.

## Old Fashioned Queue

public class Scheduler
{
private BackgroundWorker _processor = new BackgroundWorker();

private Queue<Action> ScheduledTasks { get; set; }

public Scheduler()
{
_processor.WorkerSupportsCancellation = true;
_processor.DoWork += (s, args) =>
{
while (!_processor.CancellationPending)
{
}
}

_processor.RunWorkerAsync();
}

{
}
}


## New Concurrent Queue

public class Scheduler
{
private BackgroundWorker _processor = new BackgroundWorker();

private ConcurrentQueue<Action> ScheduledTasks { get; set; }

public Scheduler()
{
_processor.WorkerSupportsCancellation = true;
_processor.DoWork += (s, args) =>
{
while (!_processor.CancellationPending)
{
{
}
}
}

_processor.RunWorkerAsync();
}

{
}
}

• Is there a particular reason why you don't use a ConcurrentQueue? – Şafak Gür Oct 3 '12 at 11:48
• @ŞafakGür, nope. I've just never used that class before and didn't even know it existed. – Mike Perrenoud Oct 3 '12 at 11:51
• @ŞafakGür, I have updated my answer to show use with the ConcurrentQueue(T). – Mike Perrenoud Oct 3 '12 at 11:59
• It's part of the thread-safe collections that came with the .NET 4 (They're in System.Collections.Concurrent namespace). They are lock-free and highly suited for concurrent operations like this. Might perform better (I'm not sure though). Edit: Just saw your edit. – Şafak Gür Oct 3 '12 at 11:59
• @ŞafakGür, and this is why I use Stack Overflow. I don't know everything, and so it's great when I learn new things like this! – Mike Perrenoud Oct 3 '12 at 12:04

Wow, there's a lot of complex answers here.

First, if you accept the restriction of UI-thread only, this is quite simple:

public abstract class SingletonTask
{

// Must be called from UI thread.
{
}

{
try { await RunProcessAsync(); }
finally { _runningTask = null; }
}

}


The code above uses the UI thread as a synchronization mechanism. So, _runningTask is always written to from the UI thread (and read from there as well). The coalescing of tasks is handled by just keeping a single "current" instance.

Extending this to be multithreaded is a bit trickier:

public abstract class SingletonTask
{
private object _mutex = new object();

{
lock (_mutex)
{
}
tcs.SetResult(null);
return result;
}


In this case, we need a _mutex for mutual exclusion. The other tricky part is that we don't want to call RunProcessAsync while holding a lock (as a general rule, you should never invoke arbitrary code while holding a lock). So, I use a "signal" (tcs) to get the Task from StartNewRunAsync before it actually invokes RunProcessAsync. That way I can update _runningTask still within the lock and then tell it to really start running at the tcs.SetResult(null) line. When it completes, it just sets _runningTask to null, so the next time RunAsync takes the lock, it'll start a new one.