Usage of vTaskSuspend and vTaskResume

I have a task which I’d need to suspend if a certain condition isn’t true, and resume otherwise. Does the following approach look okay? I didn’t put a lock in here since subscribed pointer is modified within the same thread.
Plus would subscribed have to be volatile given it’s not modified in an ISR?

Alsoo I just realized this approach will probably not work since the thread needs to be woken up by somewhere else once it’s suspended, yes? One way would’ve been invoking vTaskSuspend() inside detach() but it exists in a Subject class which is a parent class of Sensor class…

Lastly, what happens when you invoke vTaskResume() when the task is already resumed? Any way to check if the task isn’t stalled prior to invoking vTaskResume?

void Subject::detach()
{
   subscribed = NULL;
}

bool Subject::ObserverSubscribed()
{
    return subscribed != NULL;
}

void Sensor::MainThread()
{
    while(true)
    {   
        /* < Pause the thread if notification manager is not subscribed  > */
        if (!ObserverSubscribed())
        {
	      vTaskSuspend(taskHandle);
        }
        else
        {
	      vTaskResume(taskHandle);	
        }
       // ....

well, the usual answer is: Implement it and see if the solution works for you. This is how we all learned the ropes.

The only input I can give is what has been posted here many times: Use external task suspensions only as a very last resort and for good reasons. Whatever issue you need to resolve - very likely there are better (meaning more stable, efficient, less prone to side effects and race conditions and easier to prove correct) ways to resolve them.

Following an established and appreciated tradition on this forum, it would be nice if you posted your results and insights here once you are done with your implementation. Thanks.

1 Like

I fully agree with @RAc and like to add:

eTaskGetState provides the information. Resuming an already resumed task does nothing. Same applies to suspend. That might cause difficulties.
However, instead of doing a likely mutexed task state query to apply a suspend/resume I’d think twice if this kind of task supervision feature (?) will really pay off resp. if there is a real life use case.
Good luck !

Basically the idea would be to stop the thread from doing sensor readings based on the user input - so I thought why not just pause the thread and resume once requested to do so…

The “normal” way to do this is for the task to suspend ITSELF and being woken up by an external source. Your proposed design - all the thread control initiated by other threads of execution - bears many unnecessary complications.

Then again, if you believe there is merit in doing it that way - again, go ahead and implement it. The results will doubtlessly be of interest to the community.

so the normal way is to check for a condition inside a thread itself, and based on that suspend the thread?

void Sensor::MainThread()
{
    while(true)
    {   
       if (!ObservedSubscribed())
       { 
          vTaskSuspend(taskHandle);
       }
  
    }
}

Furx, the BEST way to solve any computational problem is to find a description of the control flow that most naturally and organically models the task at hand.

Many functioning architectures I’ve seen work can be descibed as such: If a task can’t proceed in what it needs to do without external input such as I/O or user input, the task suspends itself by waiting for an event (in the form of a semaphore, mailbox, notification or other appropriate means). The other thread of execution that provides the input signals the event, thus allowing the waiting task to continue.

It does happen that a taks calls vTaskSuspend(NULL) for that purpose, and the event provider calls vTaskResume() (or -FromISR) after storing the information needed by the suspended task in locations accessible by both threads. Nothing wrong with that, although in most use cases a semaphore can be used to accomplish the same result.

Again, if you have the liberty to muse about architectures, go ahead and implement them. That’s the best way for you to figure out what will work and what will work better.

1 Like

Actually, there is one FUNDAMENTAL problem with this sort of use of Suspend/Resume, it has a race condition, which is where the semaphore/task notification works better.

Between the time that the suspending task determines that it doesn’t have anything to do and it actually suspends itself is a window for a race. If during that window, the event that the task is supposed to handle occurs, the resume will occur BEFORE the suspend, and the task will stay suspended. The better answer is to use a semaphore or a task notification which WILL remember that it was signaled before the request to wait, and let the task continue.

From what I see, Suspend/Resume has limited uses to cases where resources are tight, and it is known that the wait for the wakeup can’t happen for long enough that the task WILL get through the suspend call before the resume happens.

This race is easy to overlook, and may be VERY intermittent, and thus hard to find, but may fail at the most inopportune time.

Currently, I have onSubscriberChange which is invoked every time the request to detach/attach the observer from the Sensor class is requested.

So if there’s a request to detach, vTaskSuspend is called which shall suspend the read thread and otherwise the task is resumed.

And what you implied was the possibility of resuming the thread during the time it’s being suspended therefore resulting in the task not resuming, yes? I don’t think this issue shall be caused here since you either resume or suspend at a certain time, no? I might be missing out some nontrivial things but let’s hear your say

void Sensor::onSubscriberChange(bool resumeThread)
{
    if (resumeThread)
    {
        if (!firstRead)
        {
	     vTaskResume(taskHandle);
        }
    }
    else
    {
        vTaskSuspend(taskHandle);
    }
}

I agree with others, suspend/resume is likely a poor design choice. It sounds like you are trying to have a thread free-run and hence you need to suspend it when you are oversubscribed. Generally, it is much better to have your system data-driven. I.e., give it work by putting data in the queue – no work +> no data I the queue, things stop naturally.

Sure, I agree with your point to have threads blocked on queues but this particular thread is constantly reading sensor data so it’s not really blocked until the observer no longer requires this reading…So how do you make use of queues in such context?
with pthreads, the following seems like a common approach:

while(1)
{
    pthread_mutex_lock(&lock);
    while(!play) { /* We're paused */
        pthread_cond_wait(&cond, &lock); /* Wait for play signal */
    }
    pthread_mutex_unlock(&lock);
    // continue with the rest of the thread...
}

Or maybe something like this where you have a queue that times out every delay and only reads sensor data when the state is not subscribed, however, the queue shall not remain blocked till it only receives something though.

void Sensor::MainThread()
{
    if (xQueueReceive(messageQueue, &msg, delay) != pdPASS)
    {
        if (state != UNSUBSCRIBED)
        {
              // continue reading sensor data
        }
    }
    else
    {
        switch (msg)
        {
              case UNSUBCRIBED:
                 state = UNSUBCRIBED;
                 break;
            // ...
         }
     }     
}