/ components / pthread / test / test_pthread_cxx.cpp
test_pthread_cxx.cpp
  1  #include <iostream>
  2  #include <sstream>
  3  #include <thread>
  4  #include <mutex>
  5  #include "freertos/FreeRTOS.h"
  6  #include "freertos/task.h"
  7  #include "unity.h"
  8  
  9  #if __GTHREADS && __GTHREADS_CXX0X
 10  
 11  #define LOG_LOCAL_LEVEL CONFIG_LOG_DEFAULT_LEVEL
 12  #include "esp_log.h"
 13  const static char *TAG = "pthread_test";
 14  
 15  static std::mutex           mtx;
 16  static std::shared_ptr<int> global_sp_mtx; // protected by mux
 17  
 18  static std::recursive_mutex recur_mtx;
 19  static std::shared_ptr<int> global_sp_recur_mtx; // protected by recursive mux
 20  
 21  static void thread_do_nothing() {}
 22  
 23  static void thread_main()
 24  {
 25      std::cout << "thread_main CXX " << std::hex <<  std::this_thread::get_id() << std::endl;
 26      std::chrono::milliseconds dur = std::chrono::milliseconds(10);
 27  
 28      for (int i = 0; i < 10; i++) {
 29          for (int j = 0; j < 10; j++) {
 30              int old_val, new_val;
 31  
 32              // mux test
 33              mtx.lock();
 34              old_val = *global_sp_mtx;
 35              std::this_thread::yield();
 36              (*global_sp_mtx)++;
 37              std::this_thread::yield();
 38              new_val = *global_sp_mtx;
 39              mtx.unlock();
 40              std::cout << "thread " << std::hex << std::this_thread::get_id() << ": nrec " << i << " val= " << *global_sp_mtx << std::endl;
 41              TEST_ASSERT_EQUAL(old_val + 1, new_val);
 42  
 43              // sleep_for test
 44              std::this_thread::sleep_for(dur);
 45  
 46              // recursive mux test
 47              recur_mtx.lock();
 48              recur_mtx.lock();
 49              old_val = *global_sp_recur_mtx;
 50              std::this_thread::yield();
 51              (*global_sp_recur_mtx)++;
 52              std::this_thread::yield();
 53              new_val = *global_sp_recur_mtx;
 54              recur_mtx.unlock();
 55              recur_mtx.unlock();
 56              std::cout << "thread " << std::hex << std::this_thread::get_id() << ": rec " << i << " val= " << *global_sp_recur_mtx << std::endl;
 57              TEST_ASSERT_EQUAL(old_val + 1, new_val);
 58          }
 59  
 60          // sleep_until test
 61          using std::chrono::system_clock;
 62          std::time_t tt = system_clock::to_time_t(system_clock::now());
 63          struct std::tm *ptm = std::localtime(&tt);
 64          ptm->tm_sec++;
 65          std::this_thread::sleep_until(system_clock::from_time_t(mktime(ptm)));
 66      }
 67  }
 68  
 69  TEST_CASE("pthread C++", "[pthread]")
 70  {
 71      global_sp_mtx.reset(new int(1));
 72      global_sp_recur_mtx.reset(new int(-1000));
 73  
 74      std::thread t1(thread_do_nothing);
 75      t1.join();
 76  
 77      std::thread t2(thread_main);
 78      std::cout << "Detach thread " << std::hex << t2.get_id() << std::endl;
 79      t2.detach();
 80      TEST_ASSERT_FALSE(t2.joinable());
 81  
 82      std::thread t3(thread_main);
 83      std::thread t4(thread_main);
 84      if (t3.joinable()) {
 85          std::cout << "Join thread " << std::hex << t3.get_id() << std::endl;
 86          t3.join();
 87      }
 88      if (t4.joinable()) {
 89          std::cout << "Join thread " << std::hex << t4.get_id() << std::endl;
 90          t4.join();
 91      }
 92  
 93      global_sp_mtx.reset(); // avoid reported leak
 94      global_sp_recur_mtx.reset();
 95  }
 96  
 97  static void task_test_sandbox()
 98  {
 99      std::stringstream ss;
100  
101      ESP_LOGI(TAG, "About to create a string stream");
102      ESP_LOGI(TAG, "About to write to string stream");
103      ss << "Hello World!";
104      ESP_LOGI(TAG, "About to extract from stringstream");
105      ESP_LOGI(TAG, "Text: %s", ss.str().c_str());
106  }
107  
108  static void task_test_sandbox_c(void *arg)
109  {
110      bool *running = (bool *)arg;
111  
112      // wrap thread func to ensure that all C++ stack objects are cleaned up by their destructors
113      task_test_sandbox();
114  
115      ESP_LOGI(TAG, "Task stk_wm = %d", uxTaskGetStackHighWaterMark(NULL));
116      if (running) {
117          *running = false;
118          vTaskDelete(NULL);
119      }
120  }
121  
122  TEST_CASE("pthread mix C/C++", "[pthread]")
123  {
124      bool c_running = true;
125  
126      std::thread t1(task_test_sandbox);
127      xTaskCreatePinnedToCore((TaskFunction_t)&task_test_sandbox_c, "task_test_sandbox", 3072, &c_running, 5, NULL, 0);
128      while (c_running) {
129          vTaskDelay(1);
130      }
131      if (t1.joinable()) {
132          std::cout << "Join thread " << std::hex << t1.get_id() << std::endl;
133          t1.join();
134      }
135  }
136  
137  #endif