Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a thread/Task with a continuous loop?

I am looking for the correct way/structure to create a loop in a Thread/Task...

The reason for this is, i need to check the DB every 15sec for report requests.

This is what i tried so far, but i get OutOfMemoryException:

    private void ViewBase_Loaded(object sender, RoutedEventArgs e) {     //On my main view loaded start thread to check report requests.     Task.Factory.StartNew(() => CreateAndStartReportRequestTask()); }  private void CreateAndStartReportRequestTask() {     bool noRequest = false;      do     {          //Starting thread to Check Report Requests And Generate Reports          //Also need the ability to Wait/Sleep when there are noRequest.          reportRequestTask = Task.Factory.StartNew(() => noRequest = CheckReportRequestsAndGenerateReports());           if (noRequest)          {              //Sleep 15sec              reportRequestTask.Wait(15000);              reportRequestTask = null;          }          else          {              if (reportRequestTask.IsCompleted)              {                  reportRequestTask = null;              }              else              {                  //Don't want the loop to continue until the first request is done                  //Reason for this is, losts of new threads being create in CheckReportRequestsAndGenerateReports()                  //Looping until first request is done.                  do                  {                   } while (!reportRequestTask.IsCompleted);                   reportRequestTask = null;              }          }      } while (true); }  private bool CheckReportRequestsAndGenerateReports() {     var possibleReportRequest = //Some linq query to check for new requests      if (possibleReportRequest != null)     {         //Processing report here - lots of new threads/task in here as well         return false;     }     else     {         return true;     } } 

What am i doing wrong?

Is this correct way or am i total off?

EDIT:

Most important, my UI must still be responsive!

like image 577
Willem Avatar asked Sep 19 '11 13:09

Willem


People also ask

How do you run an infinite loop thread?

Java has a built in mechanism for having a thread do something and then wait for a while to do it again, called Timer . You can put what would be inside your loop inside the Run() method of a TimerTask , and then tell the timer how often you want it done.

What is the difference between a Task and a thread?

A task is something you want done. A thread is one of the many possible workers which performs that task. In . NET 4.0 terms, a Task represents an asynchronous operation.

What happens to a thread after it finishes its Task?

Thread Termination After finish their work, threads terminate. In the quicksort example, after both array subsegments are sorted, the threads created for sorting them terminate. In fact, the thread that creates these two child threads terminates too, because its assigned task completes.


2 Answers

Something like this would work:

var cancellationTokenSource = new CancellationTokenSource(); var task = Repeat.Interval(         TimeSpan.FromSeconds(15),         () => CheckDatabaseForNewReports(), cancellationTokenSource.Token); 

The Repeat class looks like this:

internal static class Repeat {     public static Task Interval(         TimeSpan pollInterval,         Action action,         CancellationToken token)     {         // We don't use Observable.Interval:         // If we block, the values start bunching up behind each other.         return Task.Factory.StartNew(             () =>             {                 for (;;)                 {                     if (token.WaitCancellationRequested(pollInterval))                         break;                      action();                 }             }, token, TaskCreationOptions.LongRunning, TaskScheduler.Default);     } }  static class CancellationTokenExtensions {     public static bool WaitCancellationRequested(         this CancellationToken token,         TimeSpan timeout)     {         return token.WaitHandle.WaitOne(timeout);     } } 
like image 157
Roger Lipscombe Avatar answered Sep 22 '22 12:09

Roger Lipscombe


Sounds like you want something like this. Please correct me if I am misinterpretting your intentions...

First, in your kick-off, set as a long running task so it doesn't consume a thread from the thread pool but creates a new one...

private void ViewBase_Loaded(object sender, RoutedEventArgs e) {     // store this references as a private member, call Cancel() on it if UI wants to stop     _cancelationTokenSource = new CancellationTokenSource();     new Task(() => CreateAndStartReportRequestTask(), _cancelationTokenSource.Token, TaskCreationOptions.LongRunning).Start(); } 

Then, in your report watching thread, loop until IsCancelRequested has been set. If there is no work, just wait on the cancel token for 15 seconds (this way if cancelled will wake sooner).

private bool CheckReportRequestsAndGenerateReports() {     while (!_cancellationTokenSource.Token.IsCancelRequested)      {         var possibleReportRequest = //Some linq query         var reportRequestTask = Task.Factory.StartNew(() => noRequest = CheckReportRequestsAndGenerateReports(), _cancellationTokenSource.Token);          if (noRequest)         {             // it looks like if no request, you want to sleep 15 seconds, right?             // so we'll wait to see if cancelled in next 15 seconds.             _cancellationTokenSource.Token.WaitHandle.WaitOne(15000);          }         else         {             // otherwise, you just want to wait till the task is completed, right?             reportRequestTask.Wait(_cancellationTokenSource.Token);         }     } } 

I'd also be wary of having your task kick off more tasks. I have a feeling you are spinning up so many you're consuming too many resources. I think the main reason your program was failing was that you had:

     if (noRequest)      {          reportRequestTask.Wait(15000);          reportRequestTask = null;      } 

This will return immediately and not wait 15s, because the thread is already complete at this point. Switching it to the cancel token (or a Thread.Sleep(), but then you can't abort it as easily) will give you the processing wait you need.

Hope this helps, let me know if i'm off on my assumptions.

like image 24
James Michael Hare Avatar answered Sep 24 '22 12:09

James Michael Hare