1

I have a windows service with a thread that runs every 2 minutes.

while (true)
{
    try
    {
        repNeg.willExecuteLoopWithTasks(param1, param2, param3);
        Thread.Sleep(20000);
    }

Inside this I have a loop with tasks:

foreach (RepModel repModelo in listaRep)
{
    Task t = new Task(() => { this.coletaFunc(repModelo.EndIp, user, tipoFilial); });
    t.Start();
}

But I think this implementation is wrong. I need to only run one task for every element in the list, and, when a specific task finishes, wait a minute and start again.

M8's I need to say i have 2 situations here.

1 - I can't wait all Task Finish. Because some task can take more then 2 hours to finish and another can take only 27 seconds.

2 - My List of tasks can change. Thats why i got a Thread. Every 2 minutes My thread get a list of Tasks to execute and then start a loop.

But sometimes my Task not Finished yet and another Thread Start Again and then strange things show in my log. I tryed to use a Dictionry to solve my problem but after some time of execution, sometimes takes days, my log show:

"System.IndexOutOfRangeException"

5
  • 1
    you don't need task, just call that function. Commented Dec 16, 2014 at 13:54
  • 1
    I think you should be looking at using the Timer Class. Your implementation is not good. I would research Asynchronous Methods. You don't want to block threads. Commented Dec 16, 2014 at 13:55
  • 1
    @Derek is it a blocked thread if it is doing the intended work? Commented Dec 16, 2014 at 13:56
  • 1
    Side note: Thread.Sleep(20000) will sleep for 20 seconds, not 2 minutes. Commented Dec 16, 2014 at 13:57
  • using Thread.Sleep is not good practice imo, What your doing is taking a thread from the threadpool, and have it do nothing for 2 minutes. thats bad practice, as it could be back in the threadppol used as a resource for something else. @DStanley Commented Dec 16, 2014 at 13:59

3 Answers 3

2

Here is what I would do...

Create a new class that stores the following (as properties):

  • a RepModel ID (something unique)
  • a DateTime for the last time ran
  • a int for the frequency the task should run in seconds
  • a bool to determine if the task is in progress or not

Then you need a global list of the class somewhere, say called "JobList".

Your main app should have a Timer, which runs every couple of minutes. The job of this timer is to check for new RepModel (assume these can change over time, i.e a database list). When this ticks, is loops the list and adds any new ones (different ID) to JobList. You may also want to remove any that are no longer required (i.e. removed from DB list).

Then you have a second timer, this runs every second. It's job is to check all items in the JobList and compare the last run time with the current time (and ensure they are not already in progress). If the duration has lapped, then kick off the task. Once the task is complete, update the last run time so it can work next time, ensuring to change the "in progress" flag as you go.

This is all theory and you will need to give it a try yourself, but I think it covers what you are actually trying to achieve.


Some sample code (may or may not compile/work):

class Job
{
    public int ID { get; set; }
    public DateTime? LastRun { get; set; }
    public int Frequency { get; set; }
    public bool InProgress { get; set; }
}

List<Job> JobList = new List<Job>();

// Every 2 minutes (or whatever).
void timerMain_Tick()
{
    foreach (RepModel repModelo in listaRep)
    {
        if(!JobList.Any(x => x.ID == repModelo.ID)
        {
            JobList.Add(new Job(){ ID = repModel.ID, Frequency = 120 });
        }
    }
}

// Every 10 seconds (or whatever).
void timerTask_Tick()
{
    foreach(var job in JobList.Where(x => !x.InProgress && (x.LastRun == null || DateTime.Compare(x.LastRun.AddSeconds(x.Duration), DateTime.Now) < 0))
    {
        Task t = new Task(() => { 
            // Do task.
        }).ContinueWith(task => {
            job.LastRun = DateTime.Now;
            job.InProgress = false;
        }, TaskScheduler.FromCurrentSynchronizationContext());;
        job.InProgress = true;
        t.Start();
    }
}
Sign up to request clarification or add additional context in comments.

8 Comments

Musefan, What will happen if one or more tasks not finished yet and MainTick start?
Not much, MainTick just keeps the list of tasks that should be processed up to date. If a big task has started running, then it will continue uneffected. It won't get run again until at least after it has finished (that is what InProgress is for)
The only bit I am not really sure about is the ContinueWith bit that updates the LastRun and InProgress. Not sure if that job object will still be available/relevant... it's too much for me to set up a test for this I'm afraid
What about Error 18 Delegate 'System.Action<System.Threading.Tasks.Task>' does not take 0 arguments this error? :(
See this I updated my code
|
0

So what you really need here is a class that has two operations, it needs to be able to start processing one of your models, and it needs to be able to end processing of one of your models. Separating it from the list will make this easier.

When you start processing a model you'll want to create a CancellationTokenSource to associate with it so that you can stop processing it later. Processing it, in your case, means having a loop, while not cancelled, that runs an operation and then waits a while. Ending the operation is as easy as cancelling the token source.

public class Foo
{
    private ConcurrentDictionary<RepModel, CancellationTokenSource> tokenLookup =
        new ConcurrentDictionary<RepModel, CancellationTokenSource>();
    public async Task Start(RepModel model)
    {
        var cts = new CancellationTokenSource();
        tokenLookup[model] = cts;
        while (!cts.IsCancellationRequested)
        {
            await Task.Run(() => model.DoWork());
            await Task.Delay(TimeSpan.FromMinutes(1));
        }
    }

    public void End(RepModel model)
    {
        CancellationTokenSource cts;
        if (tokenLookup.TryRemove(model, out cts))
            cts.Cancel();
    }
}

15 Comments

wow, look nice, but cant imagine it runing inside my loop :(. To complex for me understand this!
@PauloJardim What don't you understand? You realize that using this is as simple as calling Start when you want to start running a model and End whenever you want to stop. That's all there is to it.
where my loop go in this sample? You understand shuld be a infinite loop?
@PauloJardim The loop is already there. When you call Start it will perform the operation on the model in a loop until Stop is called.
But for every Model i will need pass diferent's param's. I Have a
|
-1

If you are using framework 4.0 and more, you may try to benefit from

Parallel.ForEach

Executes a foreach operation in which iterations may run in parallel.

Parallel code may look like this:

Parallel.ForEach(listaRep , repModelo => {
     this.coletaFunc(repModelo.EndIp, user, tipoFilial);

});

This will run on multiple cores (if that is possible), and you don't need some specific task sceduler, as your code will wait until all parallel tasks inside parallel loop are finished. And after you can call recursively the same function, if condition was met.

8 Comments

Tigran, I can't wait all task finish. Please I edited my question
@PauloJardim: so what should happen if one task is not finshed yet, and another need to be start ?
Tigran, should jump this one only.
but that is not a problem of parallel engine itself, but, a this point, the problem is in Task Scehduler, who injects into the Queue a job that not yet finished... is any given job can be uniquely identified and queried for its state of execution ?
The task is to conect to a spec specific hardware and colect some informartion about then and then save on DB. But some of this machines take a long to recovery all information. But can't wait all finished. i need this information as soo as possible
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.