std::thread : please raise the main loop prio to >2 by default (instead of 1)
as shown here the thread loop prios have to be increased to 0 to avoid blocking.
https://github.com/espressif/arduino-esp32/issues/2814
IMO it would be better to set the main loop to a higher prio by default (e.g., 3) to have a larger bandwidth fo thread prios to cooperate!
Alternatively there should be a way to increase the main loop prio arbitrarily, manually.
You can call vTaskPrioritySet(NULL, 3); from setup and it will reset the current task's priority.
Or you can compile Arduino as an IDF component and adjust the settings however you like via sdkconfig.h
the latter opion is not clear, tbh.
I always use just the Arduino IDE, nothing different
compiling by ctrl+r and uploading by ctrl+u.
as to option 1:
here I was missing a documentation that
vTaskPrioritySet(NULL, 3);
is supposed to work not just in std::threads but also in the main loop.
Thanks, I'll test that ASAP!
update:
no, that does not work:
// std::thread for ESP32, Arduino IDE
// ver 0.0.6 fibonacci
#include <Arduino.h>
#include <thread>
#include <freertos/task.h>
#ifndef LED_BUILTIN
#define LED_BUILTIN 13
#endif
const auto one_sec = std::chrono::seconds { 1 };
int fibbonacci(int n) {
if(n == 0){
return 0;
} else if(n == 1) {
return 1;
} else {
return (fibbonacci(n-1) + fibbonacci(n-2));
}
}
void blinker_loop() {
thread_local uint32_t counter = 0;
Serial.println((String)"blinker_loop Current priority :" + uxTaskPriorityGet(NULL));
vTaskPrioritySet(NULL,2);//set Priority
Serial.println((String)"blinker_loop Current priority :" + uxTaskPriorityGet(NULL));
while(true) {
digitalWrite(LED_BUILTIN, HIGH);
Serial.println((String)"blinker_loop (HIGH) counter: "+ counter);
std::this_thread::sleep_for(one_sec);
digitalWrite(LED_BUILTIN, LOW);
Serial.println((String)"blinker_loop (LOW) counter: "+ counter);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
counter++;
}
}
void fibonacci_loop() {
thread_local uint32_t counter = 0, i=0;
Serial.println((String)"fibonacci_loop Current priority :" + uxTaskPriorityGet(NULL));
vTaskPrioritySet(NULL,2);//set Priority
Serial.println((String)"fibonacci_loop Current priority :" + uxTaskPriorityGet(NULL));
while(true) {
for(i=30; i<41; i++) { // limits: test, debug
Serial.println( (String)"Fibbonacci of "+i+"="+fibbonacci(i));
}
Serial.println((String)"fibonacci_loop counter: "+counter);
counter++;
}
}
std::thread *thread_1;
std::thread *thread_2;
void setup() {
Serial.begin(115200);
delay(1000);
vTaskPrioritySet(NULL, 3);
thread_1 = new std::thread(blinker_loop);
thread_2 = new std::thread(fibonacci_loop);
}
void loop() {
delay(500);
static uint32_t main_loop_counter = 0;
Serial.println((String)"main loop: " + main_loop_counter);
delay(5000);
main_loop_counter++;
}
program breaks and restarts:
load:0x40080400,len:5868
entry 0x4008069c
blinker_loop Current priority :5
blinker_loop Current priority :2
fibonacci_loop Current priority :5blinker_loop (HIGH) counter: 0
fibonacci_loop Current priority :2
Fibbonacci of 30=832040
Fibbonacci of 31=1346269
main loop: 0
Fibbonacci of 32=2178309
blinker_loop (LOW) counter: 0
Fibbonacci of 33=3524578
blinker_loop (HIGH) counter: 1
Fibbonacci of 34=5702887
blinker_loop (LOW) counter: 1
blinker_loop (HIGH) counter: 2
blinker_loop (LOW) counter: 2
Fibbonacci of 35=9227465
blinker_loop (HIGH) counter: 3
E (12194) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (12194) task_wdt: - IDLE0 (CPU 0)
E (12194) task_wdt: Tasks currently running:
E (12194) task_wdt: CPU 0: pthread
E (12194) task_wdt: CPU 1: IDLE1
E (12194) task_wdt: Aborting.
abort() was called at PC 0x400d6573 on core 0
Backtrace: 0x40089150:0x3ffbe160 0x4008937d:0x3ffbe180 0x400d6573:0x3ffbe1a0 0x40081671:0x3ffbe1c0 0x400ea4f9:0x3ffb93d0 0x400ea4f1:0x3ffb93f0 0x400ea4f1:0x3ffb9410 0x400ea4f1:0x3ffb9430 0x400ea4f1:0x3ffb9450 0x400ea4f1:0x3ffb9470 0x400ea4f1:0x3ffb9490 0x400ea4f1:0x3ffb94b0 0x400ea4f1:0x3ffb94d0 0x400ea4f1:0x3ffb94f0 0x400ea4f1:0x3ffb9510 0x400ea4f1:0x3ffb9530 0x400ea4f1:0x3ffb9550 0x400ea4f1:0x3ffb9570 0x400ea4f1:0x3ffb9590 0x400ea4f1:0x3ffb95b0 0x400d1063:0x3ffb95d0 0x400ea4dd:0x3ffb9620 0x400e6e65:0x3ffb9640 0x400e5f30:0x3ffb9670 0x40087c9d:0x3ffb9690
Rebooting...
ets Jun 8 2016 00:22:57
rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:928
ho 0 tail 12 room 4
load:0x40078000,len:8424
ho 0 tail 12 room 4
load:0x40080400,len:5868
entry 0x4008069c
blinker_loop Current priority :5
blinker_loop Current priority :2
fibonacci_loop Current priority :5blinker_loop (HIGH) counter: 0
fibonacci_loop Current priority :2
Fibbonacci of 30=832040
Fibbonacci of 31=1346269
main loop: 0
Fibbonacci of 32=2178309
blinker_loop (LOW) counter: 0
Fibbonacci of 33=3524578
blinker_loop (HIGH) counter: 1
Fibbonacci of 34=5702887
blinker_loop (LOW) counter: 1
blinker_loop (HIGH) counter: 2
blinker_loop (LOW) counter: 2
Fibbonacci of 35=9227465
blinker_loop (HIGH) counter: 3
E (12195) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (12195) task_wdt: - IDLE0 (CPU 0)
E (12195) task_wdt: Tasks currently running:
E (12195) task_wdt: CPU 0: pthread
E (12195) task_wdt: CPU 1: IDLE1
E (12195) task_wdt: Aborting.
abort() was called at PC 0x400d6573 on core 0
Backtrace: 0x40089150:0x3ffbe160 0x4008937d:0x3ffbe180 0x400d6573:0x3ffbe1a0 0x40081671:0x3ffbe1c0 0x400ea4f9:0x3ffb93d0 0x400ea4f1:0x3ffb93f0 0x400ea4f1:0x3ffb9410 0x400ea4f1:0x3ffb9430 0x400ea4f1:0x3ffb9450 0x400ea4f1:0x3ffb9470 0x400ea4f1:0x3ffb9490 0x400ea4f1:0x3ffb94b0 0x400ea4f1:0x3ffb94d0 0x400ea4f1:0x3ffb94f0 0x400ea4f1:0x3ffb9510 0x400ea4f1:0x3ffb9530 0x400ea4f1:0x3ffb9550 0x400ea4f1:0x3ffb9570 0x400ea4f1:0x3ffb9590 0x400ea4f1:0x3ffb95b0 0x400d1063:0x3ffb95d0 0x400ea4dd:0x3ffb9620 0x400e6e65:0x3ffb9640 0x400e5f30:0x3ffb9670 0x40087c9d:0x3ffb9690
Rebooting...
ets Jun 8 2016 00:22:57
rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:928
ho 0 tail 12 room 4
load:0x40078000,len:8424
ho 0 tail 12 room 4
load:0x40080400,len:5868
entry 0x4008069c
blinker_loop Current priority :5
blinker_loop Current priority :2
fibonacci_loop Current priority :5blinker_loop (HIGH) counter: 0
fibonacci_loop Current priority :2
Fibbonacci of 30=832040
Fibbonacci of 31=1346269
main loop: 0
Fibbonacci of 32=2178309
blinker_loop (LOW) counter: 0
Fibbonacci of 33=3524578
blinker_loop (HIGH) counter: 1
Fibbonacci of 34=5702887
blinker_loop (LOW) counter: 1
blinker_loop (HIGH) counter: 2
blinker_loop (LOW) counter: 2
Fibbonacci of 35=9227465
blinker_loop (HIGH) counter: 3
E (12195) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (12195) task_wdt: - IDLE0 (CPU 0)
E (12195) task_wdt: Tasks currently running:
E (12195) task_wdt: CPU 0: pthread
E (12195) task_wdt: CPU 1: IDLE1
E (12195) task_wdt: Aborting.
abort() was called at PC 0x400d6573 on core 0
Backtrace: 0x40089150:0x3ffbe160 0x4008937d:0x3ffbe180 0x400d6573:0x3ffbe1a0 0x40081671:0x3ffbe1c0 0x400ea4f9:0x3ffb93d0 0x400ea4f1:0x3ffb93f0 0x400ea4f1:0x3ffb9410 0x400ea4f1:0x3ffb9430 0x400ea4f1:0x3ffb9450 0x400ea4f1:0x3ffb9470 0x400ea4f1:0x3ffb9490 0x400ea4f1:0x3ffb94b0 0x400ea4f1:0x3ffb94d0 0x400ea4f1:0x3ffb94f0 0x400ea4f1:0x3ffb9510 0x400ea4f1:0x3ffb9530 0x400ea4f1:0x3ffb9550 0x400ea4f1:0x3ffb9570 0x400ea4f1:0x3ffb9590 0x400ea4f1:0x3ffb95b0 0x400d1063:0x3ffb95d0 0x400ea4dd:0x3ffb9620 0x400e6e65:0x3ffb9640 0x400e5f30:0x3ffb9670 0x40087c9d:0x3ffb9690
Rebooting...
ets Jun 8 2016 00:22:57
rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:928
ho 0 tail 12 room 4
load:0x40078000,len:8424
ho 0 tail 12 room 4
load:0x40080400,len:5868
entry 0x4008069c
blinker_loop Current priority :5
blinker_loop Current priority :2
fibonacci_loop Current priority :5blinker_loop (HIGH) counter: 0
fibonacci_loop Current priority :2
Fibbonacci of 30=832040
Fibbonacci of 31=1346269
main loop: 0
Fibbonacci of 32=2178309
blinker_loop (LOW) counter: 0
Fibbonacci of 33=3524578
blinker_loop (HIGH) counter: 1
Fibbonacci of 34=5702887
blinker_loop (LOW) counter: 1
blinker_loop (HIGH) counter: 2
blinker_loop (LOW) counter: 2
Fibbonacci of 35=9227465
blinker_loop (HIGH) counter: 3
E (12195) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (12195) task_wdt: - IDLE0 (CPU 0)
E (12195) task_wdt: Tasks currently running:
E (12195) task_wdt: CPU 0: pthread
E (12195) task_wdt: CPU 1: IDLE1
E (12195) task_wdt: Aborting.
abort() was called at PC 0x400d6573 on core 0
Backtrace: 0x40089150:0x3ffbe160 0x4008937d:0x3ffbe180 0x400d6573:0x3ffbe1a0 0x40081671:0x3ffbe1c0 0x400ea4f9:0x3ffb93d0 0x400ea4f1:0x3ffb93f0 0x400ea4f1:0x3ffb9410 0x400ea4f1:0x3ffb9430 0x400ea4f1:0x3ffb9450 0x400ea4f1:0x3ffb9470 0x400ea4f1:0x3ffb9490 0x400ea4f1:0x3ffb94b0 0x400ea4f1:0x3ffb94d0 0x400ea4f1:0x3ffb94f0 0x400ea4f1:0x3ffb9510 0x400ea4f1:0x3ffb9530 0x400ea4f1:0x3ffb9550 0x400ea4f1:0x3ffb9570 0x400ea4f1:0x3ffb9590 0x400ea4f1:0x3ffb95b0 0x400d1063:0x3ffb95d0 0x400ea4dd:0x3ffb9620 0x400e6e65:0x3ffb9640 0x400e5f30:0x3ffb9670 0x40087c9d:0x3ffb9690
Rebooting...
ets Jun 8 2016 00:22:57
You are triggering the WDT since your std::thread impl doesn't delay to allow timeslicing. We have covered that in your issue about std::thread previously.
I have to disagree:
leaving main loop by default prio=1,
and setting
vTaskPrioritySet(NULL, 0);
in either std::thread, then it works like a charm
but then being always limited to thread prios 0, nothing different. (prio 1 would break it, too).
E (12195) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (12195) task_wdt: - IDLE0 (CPU 0)
E (12195) task_wdt: Tasks currently running:
E (12195) task_wdt: CPU 0: pthread
E (12195) task_wdt: CPU 1: IDLE1
E (12195) task_wdt: Aborting.
abort() was called at PC 0x400d6573 on core 0
You can disagree all you want but the above is what is causing your failure. You MUST have a delay in your tasks otherwise there will not be any task switching and the IDLEX task will be starved from execution and trigger the watchdog timer.
You are not limited to priority zero, it works at that level as it is at the same priority as the IDLEX tasks. Nothing more, nothing less. If you add a small delay, like vTaskDelay(1), you can use almost any priority and it will work as you expect.
no, you're wrong: I do not have to have a delay.
As stated, all runs fine with this program, no delays at all (and that way a preemptive MT program is supposed to work):
// std::thread for ESP32, Arduino IDE
// ver 0.0.6 fibonacci
#include <Arduino.h>
#include <thread>
#include <freertos/task.h>
#ifndef LED_BUILTIN
#define LED_BUILTIN 13
#endif
const auto one_sec = std::chrono::seconds
{
1
};
int fibbonacci(int n) {
if(n == 0){
return 0;
} else if(n == 1) {
return 1;
} else {
return (fibbonacci(n-1) + fibbonacci(n-2));
}
}
void blinker_loop() {
thread_local uint32_t counter = 0;
Serial.println((String)"blinker_loop Current priority :" + uxTaskPriorityGet(NULL));
vTaskPrioritySet(NULL,0);//set Priority
Serial.println((String)"blinker_loop Current priority :" + uxTaskPriorityGet(NULL));
while(true) {
digitalWrite(LED_BUILTIN, HIGH);
Serial.println((String)"blinker_loop (HIGH) counter: "+ counter);
std::this_thread::sleep_for(one_sec);
digitalWrite(LED_BUILTIN, LOW);
Serial.println((String)"blinker_loop (LOW) counter: "+ counter);
std::this_thread::sleep_for(one_sec);
counter++;
}
}
void fibonacci_loop() {
thread_local uint32_t counter = 0, i=0;
Serial.println((String)"fibonacci_loop Current priority :" + uxTaskPriorityGet(NULL));
vTaskPrioritySet(NULL,0);//set Priority
Serial.println((String)"fibonacci_loop Current priority :" + uxTaskPriorityGet(NULL));
while(true) {
for(i=30; i<41; i++) { // limits: test, debug
Serial.println( (String)"Fibbonacci of "+i+"="+fibbonacci(i));
}
Serial.println((String)"fibonacci_loop counter: "+counter);
counter++;
}
}
std::thread *thread_1;
std::thread *thread_2;
void setup() {
Serial.begin(115200);
delay(1000);
thread_1 = new std::thread(blinker_loop);
thread_2 = new std::thread(fibonacci_loop);
}
void loop() {
delay(500);
static uint32_t main_loop_counter = 0;
Serial.println((String)"main loop: " + main_loop_counter);
delay(5000);
main_loop_counter++;
}
output:
```
blinker_loop Current priority :5
blinker_loop Current priority :0
fibonacci_loop Current priority :5
blinker_loop (HIGH) counter: 0
fibonacci_loop Current priority :0
Fibbonacci of 30=832040
main loop: 0
Fibbonacci of 31=1346269
blinker_loop (LOW) counter: 0
Fibbonacci of 32=2178309
blinker_loop (HIGH) counter: 1
Fibbonacci of 33=3524578
blinker_loop (LOW) counter: 1
blinker_loop (HIGH) counter: 2
Fibbonacci of 34=5702887
blinker_loop (LOW) counter: 2
main loop: 1
blinker_loop (HIGH) counter: 3
blinker_loop (LOW) counter: 3
blinker_loop (HIGH) counter: 4
Fibbonacci of 35=9227465
blinker_loop (LOW) counter: 4
blinker_loop (HIGH) counter: 5
blinker_loop (LOW) counter: 5
main loop: 2
blinker_loop (HIGH) counter: 6
blinker_loop (LOW) counter: 6
Fibbonacci of 36=14930352
blinker_loop (HIGH) counter: 7
blinker_loop (LOW) counter: 7
blinker_loop (HIGH) counter: 8
main loop: 3
blinker_loop (LOW) counter: 8
blinker_loop (HIGH) counter: 9
blinker_loop (LOW) counter: 9
blinker_loop (HIGH) counter: 10
blinker_loop (LOW) counter: 10
Fibbonacci of 37=24157817
blinker_loop (HIGH) counter: 11
main loop: 4
blinker_loop (LOW) counter: 11
blinker_loop (HIGH) counter: 12
blinker_loop (LOW) counter: 12
blinker_loop (HIGH) counter: 13
blinker_loop (LOW) counter: 13
main loop: 5
blinker_loop (HIGH) counter: 14
blinker_loop (LOW) counter: 14
blinker_loop (HIGH) counter: 15
blinker_loop (LOW) counter: 15
blinker_loop (HIGH) counter: 16
blinker_loop (LOW) counter: 16
main loop: 6
blinker_loop (HIGH) counter: 17
blinker_loop (LOW) counter: 17
Fibbonacci of 38=39088169
blinker_loop (HIGH) counter: 18
blinker_loop (LOW) counter: 18
blinker_loop (HIGH) counter: 19
main loop: 7
blinker_loop (LOW) counter: 19
blinker_loop (HIGH) counter: 20
blinker_loop (LOW) counter: 20
blinker_loop (HIGH) counter: 21
blinker_loop (LOW) counter: 21
blinker_loop (HIGH) counter: 22
main loop: 8
blinker_loop (LOW) counter: 22
blinker_loop (HIGH) counter: 23
blinker_loop (LOW) counter: 23
blinker_loop (HIGH) counter: 24
blinker_loop (LOW) counter: 24
main loop: 9
blinker_loop (HIGH) counter: 25
blinker_loop (LOW) counter: 25
blinker_loop (HIGH) counter: 26
blinker_loop (LOW) counter: 26
blinker_loop (HIGH) counter: 27
blinker_loop (LOW) counter: 27
main loop: 10
blinker_loop (HIGH) counter: 28
blinker_loop (LOW) counter: 28
blinker_loop (HIGH) counter: 29
Fibbonacci of 39=63245986
blinker_loop (LOW) counter: 29
blinker_loop (HIGH) counter: 30
main loop: 11
blinker_loop (LOW) counter: 30
blinker_loop (HIGH) counter: 31
blinker_loop (LOW) counter: 31
blinker_loop (HIGH) counter: 32
blinker_loop (LOW) counter: 32
blinker_loop (HIGH) counter: 33
main loop: 12
blinker_loop (LOW) counter: 33
blinker_loop (HIGH) counter: 34
blinker_loop (LOW) counter: 34
blinker_loop (HIGH) counter: 35
blinker_loop (LOW) counter: 35
main loop: 13
blinker_loop (HIGH) counter: 36
blinker_loop (LOW) counter: 36
blinker_loop (HIGH) counter: 37
blinker_loop (LOW) counter: 37
blinker_loop (HIGH) counter: 38
blinker_loop (LOW) counter: 38
main loop: 14
blinker_loop (HIGH) counter: 39
blinker_loop (LOW) counter: 39
blinker_loop (HIGH) counter: 40
blinker_loop (LOW) counter: 40
blinker_loop (HIGH) counter: 41
main loop: 15
blinker_loop (LOW) counter: 41
blinker_loop (HIGH) counter: 42
blinker_loop (LOW) counter: 42
blinker_loop (HIGH) counter: 43
blinker_loop (LOW) counter: 43
blinker_loop (HIGH) counter: 44
main loop: 16
blinker_loop (LOW) counter: 44
blinker_loop (HIGH) counter: 45
blinker_loop (LOW) counter: 45
blinker_loop (HIGH) counter: 46
blinker_loop (LOW) counter: 46
main loop: 17
blinker_loop (HIGH) counter: 47
Fibbonacci of 40=102334155
fibonacci_loop counter: 0
Fibbonacci of 30=832040
blinker_loop (LOW) counter: 47
Fibbonacci of 31=1346269
blinker_loop (HIGH) counter: 48
Fibbonacci of 32=2178309
blinker_loop (LOW) counter: 48
Fibbonacci of 33=3524578
blinker_loop (HIGH) counter: 49
blinker_loop (LOW) counter: 49
main loop: 18
Fibbonacci of 34=5702887
blinker_loop (HIGH) counter: 50
blinker_loop (LOW) counter: 50
blinker_loop (HIGH) counter: 51
Fibbonacci of 35=9227465
blinker_loop (LOW) counter: 51
blinker_loop (HIGH) counter: 52
main loop: 19
blinker_loop (LOW) counter: 52
blinker_loop (HIGH) counter: 53
blinker_loop (LOW) counter: 53
blinker_loop (HIGH) counter: 54
Fibbonacci of 36=14930352
blinker_loop (LOW) counter: 54
blinker_loop (HIGH) counter: 55
main loop: 20
blinker_loop (LOW) counter: 55
```
as you can see, it runs fine with thread prios=0, but just 0,
because main loop has prio=1, whilst the watchdog is feeded then by the main loop.
My point in this topic is about raising the main loop prio to e.g. =3,
so then threads may have prio=0, 1,or 2 w/o blocking and watchdog issues.
as you can see, it runs fine with thread prios=0, but just 0,
because main loop has prio=1, whilst the watchdog is feeded then by the main loop.
Sorry but your loop() task does NOT feed the watchdog. In fact none of your code does! That is why you are only able to use priority 0 for your tasks, they share the same priority as the IDLEX task.
The way the ESP32 FreeRTOS task scheduler works is based on task priority, it will give cycles to the highest priority task(s) until they yield (delay) to the scheduler for other tasks at lower priorities to run. There is no guarantee that lower priority tasks will be given any cycles without the higher priority tasks yielding.
Increasing the loop task priority will not solve the watchdog errors you are creating in your tasks, it will simply shift where they occur.
ok, then shift it (or raise even the IDLEX prio additionally), to enable more different thread prios (without blocking main() )!
(after all your hint
You can call vTaskPrioritySet(NULL, 3); from setup and it will reset the current task's priority.
also didn't solve problem!)
(after all your hint
You can call vTaskPrioritySet(NULL, 3); from setup and it will reset the current task's priority.
also didn't solve problem!)
Of course not, you didn't solve the problem in YOUR code which triggered the watchdog. This is a problem in YOUR code and not in arduino-esp32 or ESP-IDF.
raise even the IDLEX prio additionally
This is not feasible or supported by FreeRTOS itself.
my code is fine, it finally has to work by preemptive MT scheduling.
A preemptive scheduler has to switch the timeslices no matter of delays or not (given the thread prios are equal or less).
Only _cooperative_ MT requires delays in between.
Also with pthread on Linux (preemptive, too) my code works fine without requiring any delays.
Also note that a stalling may happen anywhere at any time randomly in a thread e.g. because of unforeseen hardware or driver problems in a thread, so either delays wouldn't help anyway.
As I think that you are no RTOS developer on ESP32 please let a developer answer and please don't capture my request any more.
how about you use the FreeRTOS API for threads? have you tried that? Do you kniow on which core your threads are allocated or you do not care for affinity? what I see is that Core0 is calling WDT and Arduino runs on Core1
@dsyleixa please be more patient, no one owes you anything here. You seem to be unfamiliar with how the preemptive scheduler in FreeRTOS works. While higher-priority tasks are active, no lower-priority tasks will get any CPU time. This is different from desktop computers and even Raspberry Pi, where lower-priority tasks still get a chance to run.
But all the tasks with the highest priority will get CPU time, that's why the scheduler is still preemptive. It switches between runnable tasks with the highest priority found in the system. As you can see, it uses scheduling algorithm different from bigger machines, because the requirements are different. This is RTOS (real-time operating system), while neither Raspberry Pi nor desktops are RTOS.
Here's a link to FreeRTOS explanation page: https://www.freertos.org/implementation/a00007.html
Here's a link to Espressif docs with some explanations about watchdog: https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/wdts.html
If your tasks can stall, the primary cause for that is a bug somewhere in your task. On bigger machines you can kill the task and restart it, but it merely hides the bug, not fixes it. Microcontrollers should never ever stall. And yes, there's some kind of watchdog in Raspberry Pi and desktop computers too to detect process stalling.
Raising IDLEX priority is useless, because it should be the task with the lowest priority, so that WDT will be reset if some other task hangs up and not gives CPU back. If it had a higher priority, then the task with lower priority could hang up undetectably. Think about it: how would you detect if your code stalls?
@me-no-dev if Core0 calls WDT and Arduino runs on Core1, then loop() can hang up and it won't reboot?
While higher-priority tasks are active, no lower-priority tasks will get any CPU time.
That is true also for pthread on Linux.
As main() is running at prio 1 and IDLEX is running probably at prio 0 , all std::threads must run also at prio 0 not to ever block main() and the entire program.
As stated, running threads at prio 0 works (see serial log above).
But wishful is to have more prios to choose, e.g. 0,1, or 2 arbitrarily (given the others are raised to 2 or 3, too).
The purpose is for bigger mobile robots to safely handle unforeseen (but possible) emergency events, not to damage the environment or even hurt or injure humans.
My request is about raising the main (and IDLEX ?) prios to have a wider range for arbitrary threads, not blocking the entire program even when they randomly might got stuck itself.
I am always only using the Arduino IDE with it's provided features.
But your thread which executes fib function takes 100% time and does not yield for a long time. If it has priority higher than 0, then Idle task doesn't get any CPU time and we have WDT reset.
From FreeRTOS point of view, your task looks like stalled - it executes and executes and never yields.
As Idle task should run at priority 0 to catch all other stalled tasks, it's not feasible to raise its priority.
Simply put, you should not execute long functions because they cannot be differentiated from stalled ones.
Your robots should avoid long functions and handle stalled ones gracefully.
And try PlatformIO instead of Arduino IDE, it's way better ;-)
my robots don't avoid long functions and also can't avoid using libs (e.g. for MPU6050) which hang up if i2c fails or whatever.
So the threads produce global timestamps (sort of heartbeat) which can be checked by main() or a different watcher thread if ok or stalling, and in that case (at least) the robot can quickly and safely be stopped.
That is the plan for ESP32 and that works already on my Pi.
The question is:
Am I strictly limited to prio=0 for unstable threads or is there a way to enable larger ranges?
You are strictly limited. But idle task already does what you want, it IS watcher thread for your stalled tasks. Periodic watchdog rearming is like a heartbeat.
I don't understand what the fuss is about.
Read about watchdog in Espressif docs (I gave the link), I think it's possible to achieve safe robot operation and handling stalled tasks.
I don't understand RTOS, I only have some knowledge about Linux pthread and a little about std::thread.
RTOS and watchdog design and functionality and all that low-level stuff is far beyond my skills.
But ok, if I am strictly limited to prio=0 , then there's no choice and I have to resign about that.
Perhaps I'll try it with the limited ESP32 std::thread features, and if I fail I'll stay with my Pi.
That's ok, of course you should stick to what's familiar with big projects.
It takes sample small programs, trial and error, to learn something new, be it RTOS or web programming, for example.
std::thread is implementation defined, there's no place in the standard that defines how it must be implemented, also pthread and std::thread in esp32 are just wrappers over a FreeRTOS task, you must yield tasks in order to allow other tasks to run
As a side note, I thought I should let you know that (as far as I understand RTOS concepts) it is guaranteed that your firmware running under RTOS will react to coming events not later than some well defined interval.
Desktop OS isn't RTOS (without special kernel tuning) and therefore cannot provide such guarantee. It will react satisfactorily most of the time, especially if the machine has some extra CPU power, but it can't be proven mathematically.
So if your robot runs on Linux, there's always a possibility that OS might decide to run its internal tasks (swapping, logging, disk checking, for examples) and miss the critical event it should have reacted to. Because kernel always has higher priority than user code.
that is not true - instead, true is:
...but as stated, for ESP32 the program above is running fine by thread prios limited to =0
that is not true:
* preemptive multitasking does not require yields for equal thread prios * on Linux the thread prios can be set higher than standard kernel thread prios (e.g., SCHED_RR, prio=80) * and if required: additionally Linux programs can be compiled to use cpu cores exclusively without enabling kernel access (no need to use that so far for my personal purposes yet though) * but as stated, for ESP32 the program above is running fine by thread prios limited to =0
I'm not talking about Linux when i said that you must yield tasks in order to allow other tasks to run (indeed CPU starvation is bad even in a GPOS), I'm talking about ESP32, indeed ESP32 have a preemptive scheduler, but running all tasks in the same priority as the idle task is a bad design. Please, read Watchdog and this "fundamental" section FreeRTOS Task
Even if you use SCHED_RR in pthread, a GPOS does not provide a warranty that your thread should be executed in a exact time slice because there are other tasks with higher priorities (kernel tasks), so, Linux is not suitable for real time applications, so, if you need real time processing Linux may be a bad option even with SCHED_RR because it's not truly real-time.
If you want a full featured preemptive scheduler, why not use Linux? 🤷♂
Hey dude, if you don't know anything about embedded system, why you want to implement one and don't even care about recommendations?, also you want a microcontroller to work as a PC and it won't work in that way, people told you to read documentation about ESP32 which is in IDF (Official docs), not all the time people can give you a working example, sometimes you need to modify something that exists, so if you want your project to work without learning a RTOS, then keep it up with Raspberry, or then work and attend recommendation to feed the watchdog in tasks.
as already stated, I am already using pthread on Linux (RPi) successfully but I tried to port programs to a ESP32 for a Arduino-based community project
This is due to convenience reasons; for most Arduino uses C++ on Pi is far too cumbersome, but that is also true for RTOS; Aduino is designed for non-professional programmers, e.g. hobbyists, artists, and pupils. OTOH, also for Linux I do not have to know about how a Linux OS works in order to work with pthread, so I actually also do not want to care about how RTOS works, I just use the high level functions (C++14 std::thread, C99 pthread).
Well , it won't work that way. You'll have to learn how RTOS works if you want to run real-time applications like controlling robots.
I actually also do not want to care about how RTOS works, I just use the high level functions (C++14 std::thread, C99 pthread).
You'll have to care about how RTOS works. You'll have to call yield from time to time to let idle task run. Your std::threads working on Linux without having to call yield is pure coincidence, that behaviour is not required by any standard.
You said your threads already do some kind of heartbeat, and there is watcher thread in your program which handles stalled threads. Why are you so opposed to call yield then on ESP32? It's the same thing. I don't understand you.
that is not true - instead, true is:
* preemptive multithreading does not require yields for equal thread prios compellingly
I never said the opposite. ESP32 RTOS works that way.
* on Linux the thread prios can be set higher than standard kernel thread prios (e.g., SCHED_RR, prio=80) * std::thread prios can be set by pthread thread ID prios (via native_handle() )
You can't set std::thread priority in C++ standard portable way, am I missing something?
* and if required: additionally Linux programs can be compiled to use cpu cores exclusively without enabling kernel access (no need to use that so far for my personal purposes yet though)...but as stated, for ESP32 the program above is running fine by thread prios limited to =0
So, you need to know something about how Linux OS works after all? SCHED_RR, various schedulers, exclusive CPU core use, etc...
But in the end you're mistaken, it can't be guaranteed that your thread will have latency low enough to perform robot controlling tasks, even with exclusive CPU core use. Because to control robot, you'll need to perform I/O, and that means your thread will halt and give control to kernel (peripheral drivers). And it may be busy with its internal tasks, keeping your task (thread) frozen.
Think about it: if general purpose Linux would be suitable for real-time applications, why would people invent real-time Linux kernel patches?
no, I don't have to learn about RTOS, and I won't ever.
I also don't learn about Linux OS basics.
I am just using C++ std::thread API functions, and additionaly C99 pthread.
what pthread provides is accessable via cplusplus.com and man pthread - that is enough to know.
But this topic is not about Linux vs. RTOS, but about having more thread prios than just =0 in case a thread might stall or block.
It's up to you.
I think this issue now may safely be closed as non-issue.
But this topic is not about Linux vs. RTOS, but about having more thread prios than just =0 in case a thread might stall or block.
As we have already seen, this is not required. Threads can run at any priority, and if they stall, watchdog will intervene. That's what watchdog is for.
no, you're wrong, because watchdog then makes the program break and reboot (see above).
Since you don't want to learn and read Espressif docs on ESP32 watchdog, you're right and I'm wrong. 😀
yes, thank you, I already know that I'm right . 8-)
(just to state , I am using C++ std::thread, I don't want to use RTOS directly)
Well, it's up to you if you want to use a higher level functionality, but you need to understand how it works and why the task is restarting, the right place to learn it is the esp32 idf 🤷♂️, we can't do nothing more for you
If you don't want to use RTOS, then use the Raspberry and this Issue is over.
You are completely wrong and you don't even care, you don't want to learn something that isn't hard at all and also you expect things to work in the same way in two systems. I suggest you to left all about microcontroller, don't try to do your project in a microcontroller because you don't want to learn anything about embedded systems, so this issue is over.
Closing.
Most helpful comment
@dsyleixa please be more patient, no one owes you anything here. You seem to be unfamiliar with how the preemptive scheduler in FreeRTOS works. While higher-priority tasks are active, no lower-priority tasks will get any CPU time. This is different from desktop computers and even Raspberry Pi, where lower-priority tasks still get a chance to run.
But all the tasks with the highest priority will get CPU time, that's why the scheduler is still preemptive. It switches between runnable tasks with the highest priority found in the system. As you can see, it uses scheduling algorithm different from bigger machines, because the requirements are different. This is RTOS (real-time operating system), while neither Raspberry Pi nor desktops are RTOS.
Here's a link to FreeRTOS explanation page: https://www.freertos.org/implementation/a00007.html
Here's a link to Espressif docs with some explanations about watchdog: https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/wdts.html
If your tasks can stall, the primary cause for that is a bug somewhere in your task. On bigger machines you can kill the task and restart it, but it merely hides the bug, not fixes it. Microcontrollers should never ever stall. And yes, there's some kind of watchdog in Raspberry Pi and desktop computers too to detect process stalling.
Raising IDLEX priority is useless, because it should be the task with the lowest priority, so that WDT will be reset if some other task hangs up and not gives CPU back. If it had a higher priority, then the task with lower priority could hang up undetectably. Think about it: how would you detect if your code stalls?
@me-no-dev if Core0 calls WDT and Arduino runs on Core1, then
loop()can hang up and it won't reboot?