Check If Task Is Already Running Before Starting New

Check if task is already running before starting new

As suggested by Jon Skeet, the Task.IsCompleted is the better option.

According to MSDN:

IsCompleted will return true when the task is in one of the three
final states: RanToCompletion, Faulted, or Canceled.

But it appears to return true in the TaskStatus.WaitingForActivation state too.

check if task with specific method is already running

You should avoid async void. On a side note, I explain on my blog that the way you're using StartNew is dangerous (you should use Task.Run instead).

Applying both of these guidelines to your example, the code will look like this:

public async Task OnValueChangeAsync() 
{
var progress = new Progress<int>(i => ProgresBar.Value = i);
Image im = await Task.Run(() => MyStaticClass.MyStaticFunction(progress));
Picture = im;
}

public async void OnValueChange(object sender, EventArgs e)
{
await OnValueChangeAsync();
}

At this point, it becomes more clear how to detect whether a method is already running (since that method actually returns a Task now). One implementation is as such:

private async Task OnValueChangeImplAsync()
{
var progress = new Progress<int>(i => ProgresBar.Value = i);
Image im = await Task.Run(() => MyStaticClass.MyStaticFunction(progress));
Picture = im;
_onValueChangeTask = null;
}

private Task _onValueChangeTask;
public Task OnValueChangeAsync()
{
if (_onValueChangeTask != null)
return _onValueChangeTask;
_onValueChangeTask = OnValueChangeImplAsync();
return _onValueChangeTask;
}

public async void OnValueChange(object sender, EventArgs e)
{
await OnValueChangeAsync();
}

How to check if celery task is already running before running it again with beat?

No, Celery Beat knows nothing about the running tasks.

One way to achieve what you are trying to do is to link the task to itself. async_apply() for an example has optional parameter link and link_error which can be used to provide a signature (it can be a single task too) to run if the task finishes successfully (link) or unsuccessfully (link_error).

What I use is the following - I schedule task to run frequently (say every 5 minutes), and I use a distributed lock to make sure I always have only one instance of the task running.

Finally a reminder - you can always implement your own scheduler, and use it in your beat configuration. I was thinking about doing this in the past for exactly the same thing you want, but decided that the solution I already have is good enough for me.

ESP-IDF How to ckeck if task is already running?

eTaskGetState can be used to check if a task is already running, but such a solution can be susceptible to races. For example your task is technically still "running" when it's in fact "finishing", i.e. setting task_done = true; and preparing for exit.

A better solution could be to use a queue (or a semaphore) and have the task run continuously, waiting for the messages to arrive and processing them in a loop.

Using a semaphore, you can do xSemaphoreTake(sem, 5000 / portTICK_PERIOD_MS); to wait for either a wake-up condition or a timeout of 5 seconds, whichever comes first.

== EDIT ==

if there is no events task should wait. Only if event happens it should run the job. It should run it immediately if there was no execution in past 5 seconds. If there was an execution it should wait until 5 seconds since last execution and only then run it

You can achieve that by carefully managing the semaphore's ticks to wait. Something like this (untested):

TickType_t nextDelay = portMAX_DELAY;
TickType_t lastWakeup = 0;
const TickType_t minDelay = 5000 / portTICK_PERIOD_MS;

for (;;) {
bool signalled = xSemaphoreTake(sem, nextDelay);
TickType_t now = (TickType_t)(esp_timer_get_time() / (portTICK_PERIOD_MS * 1000));
if (signalled) {
TickType_t ticksSinceLastWakeup = now - lastWakeup;
if (ticksSinceLastWakeup < minDelay) {
// wakeup too soon - schedule next wakeup and go back to sleep
nextDelay = minDelay - ticksSinceLastWakeup;
continue;
}
}
lastWakeup = now;
nextDelay = portMAX_DELAY;

// do work ...
}

How to check if Async Task is already running

I think you should check the concept of Application in Android.
http://developer.android.com/reference/android/app/Application.html

In fact there is no such thing as

different instance of the app

. The Application is always the same for all your Activities/Services.
That means that you'd left the Activity and opened it again, 2 cases are possible:

  1. The system already killed your application. In this case AsyncTask is dead already and it's safe to start a new one
  2. The Application was still alive, so AsyncTask possibly still running.

In 2nd case I will recommend to use some static variables, pointing to this AsyncTask or it's state. If your app was still alive when 2nd time opened - all static references will be still valid, so you can successfully operate.

PS: By the way, in current approach be aware that your application can be terminated by the system at any time. So AsyncTask can be interrupted in any moment. It it's not ok for you - please check IntentServices - components, specially designed for background-operation purpose. http://developer.android.com/reference/android/app/IntentService.html

Good luck!

Await an already running task

First of all, it is OK to await the same task multiple times and it not gonna hurt your database. So, at least, you could cache such task (you're locking anyways, so it's safe) and later reuse it. That lets you to minimize locking time btw.

Secondly, since your resources are global by definition, it seems reasonable to precompute long-running query. Which means you run appropriate task right in the constructor (without awaiting it) and no locking is needed, not at all.

public MyConstructor()
{
_myCachedTask = LongRunningTask(); // don't await it; hopefully, task is now running somewhere on the thread pool
}

...

public Task LongRunningTask() => _myCachedTask; // it's OK to await it multiple times, thread safe as well

Does or does Task.Wait not start the task if it isn't already running?

Tasks are generally split into two groups - "cold" tasks and "hot" tasks. "cold" tasks are tasks that have not yet been started and are not meant to run yet. "hot" tasks are tasks that may or may not be currently running but, importantly, if they're not running yet, they may do so at any time. They're meant to be running but haven't yet been assigned the resource (a thread) they need to do so.

What this post is talking about is executing a "hot" task that hasn't otherwise had an opportunity to run. "hot" tasks are created by calling e.g. Task.Run(). They're also e.g. the type of Tasks you'll receive from async methods. new Task(...), on the other hand gives you "cold" tasks. Unless or until you call Start or moral equivalent methods on that task, it remains "cold". It's calling one of those methods explicitly that makes it "hot" instead of "cold".

Generally, you don't want to be working with "cold" tasks at all these days, which is why directly calling a Task constructor is frowned upon. They were really a bad experiment from before they worked out how scheduling should really work. Most modern code doesn't expect to be working with "cold" tasks at all.

The key quote from the above post is this one:

However, if it hasn’t started executing, Wait may be able to pull the target task out of the scheduler to which it was queued and execute it inline on the current thread.

If you've not called Start on the task, it hasn't been queued with a scheduler - so obviously we cannot do what the above says.

Check Task.Run Is Not Already Running

The Task.Run() method returns a Task object. You can, instead of immediate using await with it, assign the Task object reference to a variable, which you can then use later to check its status.

For example:

private Task _task;

private async void Window_PreviewKeyDown(object sender, KeyEventArgs e){
//check goes here - abort if running
if (_task != null && !_task.IsCompleted)
{
// Your code here -- use whatever mechanism you deem appropriate
// to interrupt the Calculate() method, e.g. call Cancel() on
// a CancellationToken you passed to the method, set a flag,
// whatever.
}

Task task = Task.Run(() => myMath.Calculate());
_task = task;
await _task;
if (task == _task)
{
// Only reset _task value if it's the one we created in this
// method call
_task = null;
}
}

Note that the above is a bit awkward. It's possible that there is a better mechanism for dealing with an already-running task in your scenario. But given the broadly stated requirement, I think the above is a reasonable approach.



Related Topics



Leave a reply



Submit