1 /* pthread/std::thread example
2 
3    This example code is in the Public Domain (or CC0 licensed, at your option.)
4 
5    Unless required by applicable law or agreed to in writing, this
6    software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
7    CONDITIONS OF ANY KIND, either express or implied.
8 */
9 
10 #include <iostream>
11 #include <thread>
12 #include <chrono>
13 #include <memory>
14 #include <string>
15 #include <sstream>
16 #include <esp_pthread.h>
17 #include <freertos/FreeRTOS.h>
18 #include <freertos/task.h>
19 #include <esp_log.h>
20 
21 using namespace std::chrono;
22 
23 const auto sleep_time = seconds
24 {
25     5
26 };
27 
print_thread_info(const char * extra=nullptr)28 void print_thread_info(const char *extra = nullptr)
29 {
30     std::stringstream ss;
31     if (extra) {
32         ss << extra;
33     }
34     ss << "Core id: " << xPortGetCoreID()
35        << ", prio: " << uxTaskPriorityGet(nullptr)
36        << ", minimum free stack: " << uxTaskGetStackHighWaterMark(nullptr) << " bytes.";
37     ESP_LOGI(pcTaskGetTaskName(nullptr), "%s", ss.str().c_str());
38 }
39 
thread_func_inherited()40 void thread_func_inherited()
41 {
42     while (true) {
43         print_thread_info("This is the INHERITING thread with the same parameters as our parent, including name. ");
44         std::this_thread::sleep_for(sleep_time);
45     }
46 }
47 
spawn_another_thread()48 void spawn_another_thread()
49 {
50     // Create a new thread, it will inherit our configuration
51     std::thread inherits(thread_func_inherited);
52 
53     while (true) {
54         print_thread_info();
55         std::this_thread::sleep_for(sleep_time);
56     }
57 }
58 
thread_func_any_core()59 void thread_func_any_core()
60 {
61     while (true) {
62         print_thread_info("This thread (with the default name) may run on any core.");
63         std::this_thread::sleep_for(sleep_time);
64     }
65 }
66 
thread_func()67 void thread_func()
68 {
69     while (true) {
70         print_thread_info();
71         std::this_thread::sleep_for(sleep_time);
72     }
73 }
74 
create_config(const char * name,int core_id,int stack,int prio)75 esp_pthread_cfg_t create_config(const char *name, int core_id, int stack, int prio)
76 {
77     auto cfg = esp_pthread_get_default_config();
78     cfg.thread_name = name;
79     cfg.pin_to_core = core_id;
80     cfg.stack_size = stack;
81     cfg.prio = prio;
82     return cfg;
83 }
84 
app_main(void)85 extern "C" void app_main(void)
86 {
87     // Create a thread using deafult values that can run on any core
88     auto cfg = esp_pthread_get_default_config();
89     esp_pthread_set_cfg(&cfg);
90     std::thread any_core(thread_func_any_core);
91 
92     // Create a thread on core 0 that spawns another thread, they will both have the same name etc.
93     cfg = create_config("Thread 1", 0, 3 * 1024, 5);
94     cfg.inherit_cfg = true;
95     esp_pthread_set_cfg(&cfg);
96     std::thread thread_1(spawn_another_thread);
97 
98     // Create a thread on core 1.
99     cfg = create_config("Thread 2", 1, 3 * 1024, 5);
100     esp_pthread_set_cfg(&cfg);
101     std::thread thread_2(thread_func);
102 
103     // Let the main task do something too
104     while (true) {
105         std::stringstream ss;
106         ss << "core id: " << xPortGetCoreID()
107            << ", prio: " << uxTaskPriorityGet(nullptr)
108            << ", minimum free stack: " << uxTaskGetStackHighWaterMark(nullptr) << " bytes.";
109         ESP_LOGI(pcTaskGetTaskName(nullptr), "%s", ss.str().c_str());
110         std::this_thread::sleep_for(sleep_time);
111     }
112 }
113