c# - How to make sure a loop within a task has run at least once -
let's have class called scheduler
contains dictionary
of <userid, task>
, task continuously loops , updates internal dictionary schedules user <userid, schedule>
information database i.e. want keep information updated in real time.
i want have method on scheduler
class getscheduleforuser
checks see if there task user , if not it'll create task wait til finishes , retrieves schedules
user (lazy load it).
my question is, after first iteration of task i'll have schedule available , can retrieve schedule...no problem first iteration need wait until task finished @ least 1 time before retrieving schedule.
i can start task , create while loop until flag set when it's finished first time loop seems me there better way , it'll useful first iteration. afterwards schedule available , won't need functionality.
does have clean way accomplish this?
the best solution can think of use taskcompletionsource
, eser mentioned in comment. here's rough code sample lots of console output make easier follow it's doing. added idisposable
scheduler calss , dictionary of cancellationtokensource
that, when you're done scheduler, can stop of tasks.
using system; using system.collections.generic; using system.linq; using system.threading; using system.threading.tasks; public class program { // helper property simplify console output public static string timestring { { return datetime.now.tostring("mm:ss.fff"); } } public static void main(string[] args) { using (var scheduler = new scheduler()) { var userid = "1"; console.writeline(timestring + " main: getting schedule first time..."); var sched1 = scheduler.getscheduleforuser(userid); console.writeline(timestring + " main: got schedule: " + sched1); console.writeline(timestring + " main: waiting 2 seconds..."); system.threading.thread.sleep(2000); console.writeline(timestring + " main: getting schedule second time..."); var sched2 = scheduler.getscheduleforuser(userid); console.writeline(timestring + " main: got schedule: " + sched2); } console.writeline(); console.writeline("press key end . . ."); console.readkey(); } } public class scheduler : idisposable { // helper property simplify console output public static string timestring { { 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; } public scheduler() { tasksdictionary = new dictionary<string, task>(); taskcompletionsourcesdictionary = new dictionary<string, taskcompletionsource<bool>>(); cancellationtokensourcesdictionary = new dictionary<string, cancellationtokensource>(); schedulesdictionary = new dictionary<string, string>(); } public void dispose() { if (tasksdictionary != null) { if (cancellationtokensourcesdictionary != null) { foreach (var tokensource in cancellationtokensourcesdictionary.values) tokensource.cancel(); task.waitall(tasksdictionary.values.toarray(), 10000); cancellationtokensourcesdictionary = null; } tasksdictionary = null; } cancellationtokensourcesdictionary = null; schedulesdictionary = null; } public string getscheduleforuser(string userid) { // there's schedule, if (schedulesdictionary.containskey(userid)) { console.writeline(timestring + " getschedule: had schedule user " + userid); return schedulesdictionary[userid]; } // if there's no task yet, start 1 if (!tasksdictionary.containskey(userid)) { console.writeline(timestring + " getschedule: starting task 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 user " + userid); } // if there's task running, wait console.writeline(timestring + " getschedule: waiting first run complete user " + userid); var temp = taskcompletionsourcesdictionary[userid].task.result; console.writeline(timestring + " getschedule: first run complete 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 userid " + userid); bool firstrun = true; while (!token.iscancellationrequested) { // simulate work while building schedule if (token.waithandle.waitone(1000)) break; // update schedule schedulesdictionary[userid] = "schedule set @ " + datetime.now.toshorttimestring(); console.writeline(timestring + " task: updated schedule userid " + userid); // if first run, set result taskcompletionsource if (firstrun) { tcs.setresult(true); firstrun = false; } } console.writeline(timestring + " task: ended task userid " + userid); } }
here's fiddle show in action: .net fiddle
Comments
Post a Comment