Saubona and Hello,
My first post here, so be gentle please. I am still feeling my way about ARM, Mbed and this environment, site and forum.
I have set up some blurb as an intro in my profile. I am trying to get a little up the ARm learning curve using MBed Studio 1.1.0, and I got a Nucleo-F446ZE to play with a few days ago.
I have some basic stuff working, blinky, ADC, buttons etc, but now I am experimenting with threads, but hit my head in trying to re-start a thread that ended.
The full code is appended, but the issue looks like it is here:-
printf (“status A: %d \n”, thread.get_state());
if (thread.get_state() == Thread::Deleted)
{
printf ("status B: %d \n", thread.get_state());
thread.start(led2_thread); // kick off the thread again
}
. . . to continue
I am trying to use if (thread.get_state() == Thread::Deleted) to see if the thread has ended, and it seems to work.
I then use
thread.start(led2_thread); // kick off the thread again to try to kick it off again but that seems to be the bit that does not work, It does not seem to restart.
I am wondering the best way to check if a thread has ‘died’ and then kick it off again.
Beginner question ?
Peter
Full code :- #include “mbed.h”
// ============= global definitions ============
// create two LED objects
DigitalOut led1(LED1);
DigitalOut led2(LED2);
// create a thread
Thread thread;
// create a procedure that will be run as a thread
void led2_thread()
{
// loop 20 times and then die
for (int i = 0; i < 21 i++)
{
led2 = !led2; // toggle the LED
ThisThread::sleep_for(2500); // take a nap
}
}
// main entry point - will run as a thread
int main()
{
Timer t // create a timer to terminate
t.start() // start the timer
thread.start(led2_thread); // kick off the thread first time
while (true)
{
led1 = !led1; // toggle the LED
ThisThread::sleep_for(1000)
printf ("status A: %d \n", thread.get_state());
if (thread.get_state() == Thread::Deleted)
{
printf ("status B: %d \n", thread.get_state());
thread.start(led2_thread); // kick off the thread again
}
if ( chrono::duration_cast<chrono::seconds>(t.elapsed_time()).count() > 100 ) // die with dignity
{
printf ("status C: %d \n", thread.get_state());
led1.write(0)
led2.write(0)
break
}
}
for better reading of your code, please be so kind and use following method
```
//your code
```
I am not professional but I think that is normal behavior. Once thread ends , it can’t be started again. You must create new one instead or make a rules inside the thread.
Thanks for the help, my post was a bit of a mess - still coming to grips with this forum !!
Thanks for the posting tips - needed
Okay - I will try to re-create a thread in main and see what happens.
Aah - so that’s how to edit.
But it seems, from some research, that threads are more complex that I thought. More research needed - but that’s why I am here
Creating and deleting threads is expensive, I wouldn’t do it. You can add a loop and wait for a semaphore. After the action inside the thread has finished, it will wait at the semaphore for the next trigger. This blocking will not consume cpu power.
Another way is to schedule functions as events in an EventQueue, this will work even in bare-metal. With the limit that you have only one thread to handle the queue events.
Thanks for this.
I did some research and what I found agrees with this.
I am still trying to come to grips with all these things to assist with threading like semaphores flags and queues. Looks like good stuff to know
In the meantime I experimented with just using volatile variables to do the same thing, but I am concerned that even the use of volatile global variables may not be thread safe.
But my next iteration looked as included.
Thanks
Now to work out how to post code properly . . . .
What was meant by … and … ? I tried but it was a bit of a mess !!
And on the topic of being new to this forum, and ARM and Mbed, I have been compiling a few documents on the background to why I am trying to get up the ARM/Mbed learning curve, and my experiences so far.
My attempts at threading are discussed in Doc 09 - First steps in threading.
The docs were started to try to get a bit of interest in this environment at the Durban Makerspace, but there is not much going on there thanks to nasty Covid-19
I have just dumped the stuff here. Not sure if there is benefit or interest in this, and if there is what to do.
Now to work out how to post code properly . . . .
What was meant by … and … ? I tried but it was a bit of a mess !!
Those are back-tick characters rather than dots. On my keyboard the related key is located in the top-left corner below the Esc. But you can also copy them from Jan’s post and paste into yours.
I think I may have it . . This was my attempt at interacting with a thread, although I am still not sure if using volatile variables makes it safe.
#include "mbed.h"
// ============= global definitions ============
volatile bool toToggle ; // flag to enable or disable toggling of LED2
volatile uint8_t toggleCount ; // toggle count of LED2
// procedure that will be run as a thread
// toggle toggleCount times and then stop
void led2_thread()
{
DigitalOut led2(LED2); // create a LED object for this thread
while (true) // this thread will run forever
{
if (toToggle) // is toggling enabled ?
{
if (toggleCount > 0) // are there still toggles to do ?
{
printf ("status led2_thread: %d \n", toggleCount); // diagnostic output to console
led2 = !led2; // toggle the LED
toggleCount-- ; // update toggle count
if (toggleCount < 1 ) // has it done it's toggling ?
toToggle = false ;
}
}
ThisThread::sleep_for(1000) ;
}
}
// main entry point - will run as a thread
int main()
{
Thread thread; // create a thread
DigitalOut led1(LED1); // create a LED object for this thread
uint8_t loopCount = 0 ; // used to stop the process
toggleCount = 20 ; // initial count
toToggle = true ; // enable toggling
thread.start(led2_thread); // kick off the thread
while (true)
{
led1 = !led1; // toggle the LED
if (toToggle == false) // this will be set false in the thread
{
toggleCount = 20 ; // reset counter
toToggle = true ; // enable toggling in the thread
}
ThisThread::sleep_for(1200) ;
loopCount++ ;
if (loopCount > 75)
return 0; // stop the whole thing - rest the board !!
}
}
I need to learn about the various semaphores and those things.
A common scenario when writing multithreaded code is to protect shared resources, for example global volatile variables shared by threads, with a mutex (or semaphore) and then release that mutex to wait for a change of that data as suggested by Johannes. If you do not do this carefully, this can lead to a race condition in the code. A Condition Variable provides a safe solution to this problem by handling the wait for a state change, along with releasing and acquiring the mutex automatically during this waiting period.
#include "mbed.h"
// ============= global definitions ============
Mutex mutex;
ConditionVariable cond(mutex);
// volatile shared variables
volatile bool toToggle; // flag to enable or disable toggling of LED2
volatile uint8_t toggleCount; // toggle count of LED2
// procedure that will be run as a thread
// toggle toggleCount times and then stop
void led2_thread()
{
DigitalOut led2(LED2); // create a LED object for this thread
while (true) {
// this thread will run forever
mutex.lock(); // about to access shared variables -> lock the mutex
if (toToggle) {
// is toggling enabled ?
if (toggleCount > 0) {
// are there still toggles to do ?
printf("status led2_thread: %d \n", toggleCount);
led2 = !led2; // toggle the LED
toggleCount--; // update toggle count
if (toggleCount < 1) // has it done it's toggling ?
toToggle = false;
}
}
cond.notify_all(); // notify all waiters on this condition variable that a condition changed.
// unblocks all of the threads waiting for the condition variable.
mutex.unlock(); // unlock the mutex
ThisThread::sleep_for(1000);
}
}
// main entry point - will run as a thread
int main()
{
Thread thread; // create a thread
DigitalOut led1(LED1); // create a LED object for this thread
uint8_t loopCount = 0; // used to stop the process
toggleCount = 20; // initial count
toToggle = true; // enable toggling
thread.start(led2_thread); // kick off the thread
mutex.lock(); // about to access shared variables -> lock the mutex
while (true) {
led1 = !led1; // toggle the LED
cond.wait(); // wait for a condition to change
// Wait causes the current thread to block until the condition variable receives a notification from another thread.
// The current thread releases the mutex while inside the wait function and reacquires it upon exiting the function.
if (toToggle == false) {// this will be set false in the thread
toggleCount = 20; // reset counter
toToggle = true; // enable toggling in the thread
}
ThisThread::sleep_for(1200);
loopCount++;
if (loopCount > 75)
return 0; // stop the whole thing - rest the board !!
}
}
welcome to the forum! I’m sure your experiences of getting to grips with Arm and Mbed could be of use to other people new to both, so please don’t be afraid to share your musings.