Serial.printf in a thread causes thread to hang

Ferrograph

New member
When I use Serial.printf in a thread, it appears to work once - I see the message in the serial monitor. Main loop appears to be running (LED flash and Loop message). But the thread is either hung or crashed. Possibly this is thread safety issue. How can I use Serial.printf() in a thread? See code below.

C++:
#include <TeensyThreads.h>
#include <_Teensy.h>


// IO Pins
const int ledPin = 13;

// the setup function runs once when you press reset or power the board
void setup() {

    // Setup debug serial
    Serial.begin(115200);
    while (!Serial) { delay(100); }
    Serial.println("~ Welcome to Threaded Project ~");

    pinMode(ledPin, OUTPUT);

    
    delay(2000);
    
    int id = threads.addThread(UpdateDisplay);

}

// the loop function runs over and over again until power down or reset
void loop() {
 
    digitalWrite(ledPin, HIGH);   // set the LED on
    delay(500);                  // wait for a second
    digitalWrite(ledPin, LOW);    // set the LED off
    delay(1000);
    Serial.println("End of Loop.");// wait for a second
}

void UpdateDisplay()
{
    int progress = 0;
    while (1)
    {
        delay(200);
        
        progress++;
        if (progress > 100) progress = 1;       
        Serial.printf("Progress: %d \n", progress);
    }
}
 
You have two threads. One thread is executing loop() and the other is executing updateDisplay(). Both are calling Serial.print(), and because that is not re-entrant, it's likely to crash your program. One solution is to print only from one thread. To print from two threads, they must be cooperative, as opposed to preemptive. I haven't used TeensyThreads, but I have seen discussions on the forum about making TeensyThreads cooperative by setting the timeslice to a very large value (so it never times out) and explicitly calling yield() in each thread.
 
In my experience, I haven’t needed a threading library to do cooperative threading. It’s possible to design a simple API where each “Task” returns from its own main loop when it’s done or needing to yield. Doing a yield() via a threading library is effectively the same thing, except you do have to keep track of more state because the code doesn’t jump back to the same place. In any case, it’s an alternative, but with the added bonus of not needing a threading library. (Your opinions may differ; this is just what I do.)
 
Thanks for the replys. I didn't originally have the Serial.printf() in loop(). I put that in to see if loop continued running and it does of course. But even with the thread being the only place Serial.print is called after setup() it still hangs. I've also tried yeild().

Something else wierd though is that plain Serial.Println() works, which I didnt notice at first. Its printF that doesnt. Im not sure why that would be different?
 
Ok been trying some alternatives. If I prepare the message first with sprintf() it works ok. Not ideal though.

So something hinky with printF.

C++:
void UpdateDisplay()
{
    int progress = 0;
    while (1)
    {
        delay(200);
       
        progress++;
        if (progress > 100) progress = 1;
       
        char* message = "xxxxxxxxxxxxxxxxxxxx";
        sprintf(message,"Progess: %d \n", progress);
       
        Serial.println(message);      
    }
}
 
Back
Top