using System.Collections.Generic;
using System.Threading.Tasks;
public static string TimeString { get { return DateTime.Now.ToString("mm:ss.fff"); } }
public static void Main(string[] args)
using (var scheduler = new Scheduler())
Console.WriteLine(TimeString + " Main: Getting schedule for first time...");
var sched1 = scheduler.GetScheduleForUser(userID);
Console.WriteLine(TimeString + " Main: Got schedule: " + sched1);
Console.WriteLine(TimeString + " Main: Waiting 1 second...");
System.Threading.Thread.Sleep(1000);
Console.WriteLine(TimeString + " Main: Getting schedule for second time...");
var sched2 = scheduler.GetScheduleForUser(userID);
Console.WriteLine(TimeString + " Main: Got schedule: " + sched2);
public class Scheduler : IDisposable
public static string TimeString { get { return DateTime.Now.ToString("mm:ss.fff"); } }
private Dictionary<string, Task> TasksDictionary { get; set; }
private Dictionary<string, TaskCompletionSource<bool>> TaskCompletionSourcesDictionary { get; set; }
private Dictionary<string, CancellationTokenSource> CancellationTokenSourcesDictionary { get; set; }
private Dictionary<string, string> SchedulesDictionary { get; set; }
TasksDictionary = new Dictionary<string, Task>();
TaskCompletionSourcesDictionary = new Dictionary<string, TaskCompletionSource<bool>>();
CancellationTokenSourcesDictionary = new Dictionary<string, CancellationTokenSource>();
SchedulesDictionary = new Dictionary<string, string>();
Console.WriteLine(TimeString + " Main: Disposing Scheduler...");
if (TasksDictionary != null)
if (CancellationTokenSourcesDictionary != null)
foreach (var tokenSource in CancellationTokenSourcesDictionary.Values)
if (!Task.WaitAll(TasksDictionary.Values.ToArray(), 1000))
Console.WriteLine(TimeString + " Main: Waited 1 second for tasks to end; giving up");
foreach (var task in TasksDictionary.Values)
if (CancellationTokenSourcesDictionary != null)
foreach (var tokenSource in CancellationTokenSourcesDictionary.Values)
CancellationTokenSourcesDictionary = null;
SchedulesDictionary = null;
Console.WriteLine(TimeString + " Main: Scheduler disposed");
public string GetScheduleForUser(string userID)
if (SchedulesDictionary.ContainsKey(userID))
Console.WriteLine(TimeString + " GetSchedule: Already had schedule for user " + userID);
return SchedulesDictionary[userID];
if (!TasksDictionary.ContainsKey(userID))
Console.WriteLine(TimeString + " GetSchedule: Starting task for user " + userID);
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
TaskCompletionSourcesDictionary.Add(userID, new TaskCompletionSource<bool>());
var task = (new TaskFactory()).StartNew(() => GenerateSchedule(userID, token, TaskCompletionSourcesDictionary[userID]), token);
TasksDictionary.Add(userID, task);
CancellationTokenSourcesDictionary.Add(userID, tokenSource);
Console.WriteLine(TimeString + " GetSchedule: Started task for user " + userID);
Console.WriteLine(TimeString + " GetSchedule: Waiting for first run to complete for user " + userID);
var temp = TaskCompletionSourcesDictionary[userID].Task.Result;
Console.WriteLine(TimeString + " GetSchedule: First run complete for user " + userID);
return SchedulesDictionary.ContainsKey(userID) ? SchedulesDictionary[userID] : "null";
private void GenerateSchedule(string userID, CancellationToken token, TaskCompletionSource<bool> tcs)
Console.WriteLine(TimeString + " Task: Starting task for userID " + userID);
while (!token.IsCancellationRequested)
if (token.WaitHandle.WaitOne(500))
SchedulesDictionary[userID] = "Schedule set at " + DateTime.Now.ToShortTimeString();
Console.WriteLine(TimeString + " Task: Updated schedule for userID " + userID);
Console.WriteLine(TimeString + " Task: Ended task for userID " + userID);