detached std::thread on esp32 arduino sometimes blocks, sometimes doesn't - c++

I have some code running on ESP32 microcontroller with arduino core,
In the setup() function I wish to have some code threadPressureCalib run independently in its own thread, so I do the following:
std::unique_ptr<std::thread> sensorCalib;
void setup()
{
sensorCalib.reset(new std::thread(threadPressureCalib));
std::thread* pc = sensorCalib.get();
pc->detach();
}
void loop()
{
...
}
Then, I define threadPressureCalib() as follows:
void threadPressureCalib()
{
float pressure=0;
int count;
for(timestarted = millis();(millis()-timestarted) < 10000;)
{ // THIS ONE BLOCKS SETUP() AND LOOP() CODE EXECUTION
Serial.println("Doing things");
}
Serial.println("Doing other things");
for (count=1; count<= 5;count++)
{ //THIS ONE DOES NOT BLOCK SETUP() and LOOP()
float temp;
while(!timer2.Delay(2000)); //Not sure if this is blocking anything
do{
temp = adc_pressure();
}while(temp>104.0 || temp<70.0); //Catch errors
pressure += temp;
}
changeSetting(pressure/5.0);
return;
}
Problem: During the first for loop, the setup() function's execution is stopped (as well as loop())
During the second for loop, nothing is stopped and the rest of the code runs in parallel (as expected)
Why is it that the first half of this code blocks, and then the second half does not?
Sorry if the question is vague or improperly asked, my first q here.
Explanation of timer2 per request in comments:
timer2 is a custom timer class, timer2.Delay(TIMEOUT) stores timestamp the first time it's called and returns false on every subsequent call until the current time = TIMEOUT, then it returns true and resets itself
NonBlockDelay timer2;
//time delay function (time in seconds to delay)
// Set iTimeout to current millis plus milliseconds to wait for
/**
* Called with milliseconds to delay.
* Return true if timer expired
*
*/
//Borrowed from someone on StackOverflow...
bool NonBlockDelay::Delay (unsigned long t)
{
if(TimingActive)
{
if((millis() >iTimeout)){
TimingActive = 0;
return(1);
}
return(0);
}
iTimeout = millis() + t;
TimingActive = 1;
return(0);
};
// returns true if timer expired
bool NonBlockDelay::Timeout (void)
{
if(TimingActive){
if((millis() >iTimeout)){
TimingActive = 0;
iTimeout = 0;
return(1);
}
}
return(false);
}
// Returns the current timeout value in milliseconds
unsigned long NonBlockDelay::Time(void)
{
return iTimeout;
}

There is not enough information here to tell you the answer but it seems that you have no idea what you are doing.
std::unique_ptr<std::thread> sensorCalib;
void setup(){
sensorCalib.reset(new std::thread(threadPressureCalib));
std::thread* pc = sensorCalib.get();
pc->detach();
}
So here you store a new thread that executes threadPressureCalib then immediately detach it. Once the thread is detached the instance std::thread no longer manages it. So what's the point of even having std::unique_ptr<std::thread> sensorCalib; in the first place if it literally does nothing? Do you realize that normally you need to join the thread if you wish to wait till it's completion? Could it be that you just start a bunch of instances of these threadPressureCalib - as you probably don't verify that they finished execution - and they interfere with each other?

Related

How to get local hour efficiently?

I'm developing a service. Currently I need to get local hour for every request, since it involves system call, it costs too much.
In my case, some deviation like 200ms is OK for me.
So what's the best way to maintain a variable storing local_hour, and update it every 200ms?
static int32_t GetLocalHour() {
time_t t = std::time(nullptr);
if (t == -1) { return -1; }
struct tm *time_info_ptr = localtime(&t);
return (nullptr != time_info_ptr) ? time_info_ptr->tm_hour : -1;
}
If you want your main thread to spend as little time as possible on getting the current hour you can start a background thread to do all the heavy lifting.
For all things time use std::chrono types.
Here is the example, which uses quite a few (very useful) multithreading building blocks from C++.
#include <chrono>
#include <future>
#include <condition_variable>
#include <mutex>
#include <atomic>
#include <iostream>
// building blocks
// std::future/std::async, to start a loop/function on a seperate thread
// std::atomic, to be able to read/write threadsafely from a variable
// std::chrono, for all things time
// std::condition_variable, for communicating between threads. Basicall a signal that only signals that something has changed that might be interesting
// lambda functions : anonymous functions that are useful in this case for starting the asynchronous calls and to setup predicates (functions returning a bool)
// std::mutex : threadsafe access to a bit of code
// std::unique_lock : to automatically unlock a mutex when code goes out of scope (also needed for condition_variable)
// helper to convert time to start of day
using days_t = std::chrono::duration<int, std::ratio_multiply<std::chrono::hours::period, std::ratio<24> >::type>;
// class that has an asynchronously running loop that updates two variables (threadsafe)
// m_hours and m_seconds (m_seconds so output is a bit more interesting)
class time_keeper_t
{
public:
time_keeper_t() :
m_delay{ std::chrono::milliseconds(200) }, // update loop period
m_future{ std::async(std::launch::async,[this] {update_time_loop(); }) } // start update loop
{
// wait until asynchronous loop has started
std::unique_lock<std::mutex> lock{ m_mtx };
// wait until the asynchronous loop has started.
// this can take a bit of time since OS needs to schedule a thread for that
m_cv.wait(lock, [this] {return m_started; });
}
~time_keeper_t()
{
// threadsafe stopping of the mainloop
// to avoid problems that the thread is still running but the object
// with members is deleted.
{
std::unique_lock<std::mutex> lock{ m_mtx };
m_stop = true;
m_cv.notify_all(); // this will wakeup the loop and stop
}
// future.get will wait until the loop also has finished
// this ensures no member variables will be accessed
// by the loop thread and it is safe to fully destroy this instance
m_future.get();
}
// inline to avoid extra calls
inline int hours() const
{
return m_hours;
}
// inline to avoid extra calls
inline int seconds() const
{
return m_seconds;
}
private:
void update_time()
{
m_now = std::chrono::steady_clock::now();
std::chrono::steady_clock::duration tp = m_now.time_since_epoch();
// calculate back till start of day
days_t days = duration_cast<days_t>(tp);
tp -= days;
// calculate hours since start of day
auto hours = std::chrono::duration_cast<std::chrono::hours>(tp);
tp -= hours;
m_hours = hours.count();
// seconds since start of last hour
auto seconds = std::chrono::duration_cast<std::chrono::seconds>(tp);
m_seconds = seconds.count() % 60;
}
void update_time_loop()
{
std::unique_lock<std::mutex> lock{ m_mtx };
update_time();
// loop has started and has initialized all things time with values
m_started = true;
m_cv.notify_all();
// stop condition for the main loop, put in a predicate lambda
auto stop_condition = [this]()
{
return m_stop;
};
while (!m_stop)
{
// wait until m_cv is signaled or m_delay timed out
// a condition variable allows instant response and thus
// is better then just having a sleep here.
// (imagine a delay of seconds, that would also mean stopping could
// take seconds, this is faster)
m_cv.wait_for(lock, m_delay, stop_condition);
if (!m_stop) update_time();
}
}
std::atomic<int> m_hours;
std::atomic<int> m_seconds;
std::mutex m_mtx;
std::condition_variable m_cv;
bool m_started{ false };
bool m_stop{ false };
std::chrono::steady_clock::time_point m_now;
std::chrono::steady_clock::duration m_delay;
std::future<void> m_future;
};
int main()
{
time_keeper_t time_keeper;
// the mainloop now just can ask the time_keeper for seconds
// or in your case hours. The only time needed is the time
// to return an int (atomic) instead of having to make a full
// api call to get the time.
for (std::size_t n = 0; n < 30; ++n)
{
std::cout << "seconds now = " << time_keeper.seconds() << "\n";
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
return 0;
}
You don't need to query local time for every request because hour doesn't change every 200ms. Just update the local hour variable every hour
The most correct solution would be registering to a timer event like scheduled task on Windows or cronjobs on Linux that runs at the start of every hour. Alternatively create a timer that runs every hour and update the variable
The timer creation depends on the platform, for example on Windows use SetTimer, on Linux use timer_create. Here's a very simple solution using boost::asio which assumes that you run on the exact hour. You'll need to make some modification to allow it to run at any time, for example by creating a one-shot timer or by sleeping until the next hour
#include <chrono>
using namespace std::chrono_literals;
int32_t get_local_hour()
{
time_t t = std::time(nullptr);
if (t == -1) { return -1; }
struct tm *time_info_ptr = localtime(&t);
return (nullptr != time_info_ptr) ? time_info_ptr->tm_hour : -1;
}
static int32_t local_hour = get_local_hour();
bool running = true;
// Timer callback body, called every hour
void update_local_hour(const boost::system::error_code& /*e*/,
boost::asio::deadline_timer* t)
{
while (running)
{
t->expires_at(t->expires_at() + boost::posix_time::hour(1));
t->async_wait(boost::bind(print,
boost::asio::placeholders::error, t, count));
local_hour = get_local_hour();
}
}
int main()
{
boost::asio::io_service io;
// Timer that runs every hour and update the local_hour variable
boost::asio::deadline_timer t(io, boost::posix_time::hour(1));
t.async_wait(boost::bind(update_local_hour,
boost::asio::placeholders::error, &t));
running = true;
io.run();
std::this_thread::sleep_for(3h);
running = false; // stop the timer
}
Now just use local_hour directly instead of GetLocalHour()

How to allocate a period of time for a thread to execute?

I have a class executing in a thread.
But I only want to allow it to run for 10 seconds.
Note... I have no means of passing any boolean into the class to stop execution.
So, How can I set up a thread to terminate after 10 seconds?
The class I am testing has potential infinite recursion that may take place and it is pointless to let it run longer than 10 seconds.
TEST_METHOD(TM_ClientServer_Threads)
{
bool bDone = false;
int ii = 0;
std::thread tCounter([&bDone, &ii]()
{
// Black Box: can't touch this; can't pass in a Boolean
while(true)
{
ii++;
}
}
);
std::thread tTimer([&bDone, &tCounter]()
{
Sleep(1000);
bDone = true;
// kill the tCounter thread ?
}
);
tCounter.join();
tTimer.join();
ii = ii + 0; // break point here
}

sleep in function but not block other functions and code

I am on esp8266 module/microcontroller. I have never wrote in C++. Now I am trying to insert my own small "non blocking" function in one file file. My function should wait 5 seconds on background and then print something. But I don't want to delay whole initialization of meInit() for 5 seconds, it should be let's say parallel "non blocking" function. How is this possible please?
void meInit()
{
if (total > 20) total = 20;
value = EEPROM.read(1);
Serial.begin(115200);
Serial.setTimeout(10);
loadSettings(true);
buildMe();
initFirst();
//here I need to call "non-blocking" function with no delay and process immediatelly further
call5sFunct();
...do other functions here immediatelly without 5s delay...
}
void call5sFunct()
{
Sleep(5000);
DEBUG_PRINTLN("I am back again");
}
P.S. short sample is highly appreciated :) thx
Use std::thread to launch call5sFunct(); in other thread, like this:
//...
initFirst();
//here I need to call "non-blocking" function with no delay and process immediatelly further
std::thread t1(call5sFunct);
t1.detach();
...do other functions here immediatelly without 5s delay...
//...
You need to include #include <thread>
You must not sleep at all, but just call your function after 5 seconds have passed, in the loop function. Something like this (untested):
unsigned long start_time = 0;
bool call5sFunct_executed = false;
void meInit()
{
if (total > 20) total = 20;
value = EEPROM.read(1);
Serial.begin(115200);
Serial.setTimeout(10);
loadSettings(true);
buildMe();
initFirst();
// You cannot call it here, but in loop()
// call5sFunct();
// ...do other functions here immediatelly without 5s delay...
}
void call5sFunct()
{
DEBUG_PRINTLN("I am back again");
}
void loop()
{
unsigned long loop_time = millis();
if (!call5sFunct_executed && (loop_time - start_time >= 5000))
{
call5sFunct();
call5sFunct_executed = true;
}
// .... the rest of your loop function ...
}
However, this template must be used extensively programming microcontrollers. It would be really coumbersome and error-prone to write production code like this - but it's important you get the point.
There are many libraries that make it easy to implement asynchronous operations on arduino, hiding this mechanism. For example take a look to TaskScheduler.
Google for "arduino asynchronous functions" and you will find a lot of alternatives.

Qt timers cannot be stopped from another thread

Hy,
I'm writing my first Qt program and getting now in troubles with:
QObject::killTimer: timers cannot be stopped from another thread
QObject::startTimer: timers cannot be started from another thread
My program will communicate to a CANOpen bus for that I'm using the Canfestival Stack. The Canfestival will work with callback methods. To detects timeout in communication I setup a timer function (somehow like a watchdog). My timer package consist out of a "tmr" module, a "TimerForFWUpgrade" module and a "SingleTimer" module. The "tmr" module was originally C programmed so the static "TimerForFWUpgrade" methods will interface it. The "tmr" module will be part of a C programed Firmware update package.
The timer will work as follows. Before a message is sent I will call TMR_Set method. An then in my idle program loop with TMR_IsElapsed we check for a timer underflow. If TMR_IsElapsed I will do the errorhandling. As you see the TMR_Set method will be called continuously and restart the QTimer again and again.
The above noted errors are appearing if I start my program. Can you tell me if my concept could work? Why does this errors appear? Do I have to use additional threads (QThread) to the main thread?
Thank you
Matt
Run and Idle loop:
void run
{
// start communicate with callbacks where TMR_Set is set continously
...
while(TMR_IsElapsed(TMR_NBR_CFU) != 1);
// if TMR_IsElapsed check for errorhandling
....
}
Module tmr (interface to C program):
extern "C"
{
void TMR_Set(UINT8 tmrnbr, UINT32 time)
{
TimerForFWUpgrade::set(tmrnbr, time);
}
INT8 TMR_IsElapsed(UINT8 tmrnbr)
{
return TimerForFWUpgrade::isElapsed(tmrnbr);
}
}
Module TimerForFWUpgrade:
SingleTimer* TimerForFWUpgrade::singleTimer[NR_OF_TIMERS];
TimerForFWUpgrade::TimerForFWUpgrade(QObject* parent)
{
for(unsigned char i = 0; i < NR_OF_TIMERS; i++)
{
singleTimer[i] = new SingleTimer(parent);
}
}
//static
void TimerForFWUpgrade::set(unsigned char tmrnbr, unsigned int time)
{
if(tmrnbr < NR_OF_TIMERS)
{
time *= TimerForFWUpgrade::timeBase;
singleTimer[tmrnbr]->set(time);
}
}
//static
char TimerForFWUpgrade::isElapsed(unsigned char tmrnbr)
{
if(true == singleTimer[tmrnbr]->isElapsed())
{
return 1;
}
else
{
return 0;
}
}
Module SingleTimer:
SingleTimer::SingleTimer(QObject* parent) : QObject(parent),
pTime(new QTimer(this)),
myElapsed(true)
{
connect(pTime, SIGNAL(timeout()), this, SLOT(slot_setElapsed()));
pTime->setTimerType(Qt::PreciseTimer);
pTime->setSingleShot(true);
}
void SingleTimer::set(unsigned int time)
{
myElapsed = false;
pTime->start(time);
}
bool SingleTimer::isElapsed()
{
QCoreApplication::processEvents();
return myElapsed;
}
void SingleTimer::slot_setElapsed()
{
myElapsed = true;
}
Use QTimer for this purpose and make use of SIGNALS and SLOT for the purpose of starting and stopping the timer/s from different threads. You can emit the signal from any thread and catch it in the thread which created the timer to act on it.
Since you say you are new to Qt, I suggest you go through some tutorials before proceeding so that you will know what Qt has to offer and don't end up trying to reinvent the wheel. :)
VoidRealms is a good starting point.
You have this problem because the timers in the static array is created in Thread X, but started and stopped in Thread Y. This is not allowed, because Qt rely on thread affinity to timeout timers.
You can either create, start stop in the same thread or use signal and slots to trigger start and stop operations for timers. The signal and slot solution is a bit problematic Because you have n QTimer objects (Hint: how do you start the timer at position i?)
What you can do instead is create and initialize the timer at position tmrnbr in
TimerForFWUpgrade::set(unsigned char tmrnbr, unsigned int time)
{
singleTimer[tmrnbr] = new SingleTimer(0);
singleTimer[tmrnbr]->set(time);
}
which is executed by the same thread.
Futhermore, you don't need a SingleTimer class. You are using Qt5, and you already have all you need at your disposal:
SingleTimer::isElapsed is really QTimer::remainingTime() == 0;
SingleTimer::set is really QTimer::setSingleShot(true); QTimer::start(time);
SingleTimer::slot_setElapsed becomes useless
ThusSingleTimer::SingleTimer becomes useless and you dont need a SingleTimer class anymore
I got the errors away after changing my timer concept. I'dont use anymore my SingleTimer module. Before the QTimer I won't let timeout and maybe because of that I run into problems. Now I have a cyclic QTimer that times out every 100ms in slot function I will then count the events. Below my working code:
TimerForFWUpgrade::TimerForFWUpgrade(QObject* parent) : QObject(parent),
pTime(new QTimer(this))
{
connect(pTime, SIGNAL(timeout()), this, SLOT(slot_handleTimer()));
pTime->setTimerType(Qt::PreciseTimer);
pTime->start(100);
}
void TimerForFWUpgrade::set(unsigned char tmrnbr, unsigned int time)
{
if(tmrnbr < NR_OF_TIMERS)
{
if(timeBase != 0)
{
myTimeout[tmrnbr] = time / timeBase;
}
else
{
myTimeout[tmrnbr] = 0;
}
myTimer[tmrnbr] = 0;
myElapsed[tmrnbr] = false;
myActive[tmrnbr] = true;
}
}
char TimerForFWUpgrade::isElapsed(unsigned char tmrnbr)
{
QCoreApplication::processEvents();
if(tmrnbr < NR_OF_TIMERS)
{
if(true == myElapsed[tmrnbr])
{
return 1;
}
else
{
return 0;
}
}
else
{
return 0; // NOK
}
}
void TimerForFWUpgrade::slot_handleTimer()
{
for(UINT8 i = 0; i < NR_OF_TIMERS; i++)
{
if(myActive[i] == true)
{
myTimer[i]++;
if(myTimeout[i] < myTimer[i])
{
myTimer[i] = 0;
myElapsed[i] = true;
myActive[i] = false;
}
}
}
}

Have a timer restart every 100ms in C / C++

I am working with a application where the requirement is execute a function after every 100ms.
Below is my code
checkOCIDs()
{
// Do something that might take more than 100ms of time
}
void TimeOut_CallBack(int w)
{
struct itimerval tout_val;
int ret = 0;
signal(SIGALRM,TimeOut_CallBack);
/* Configure the timer to expire after 100000 ... */
tout_val.it_value.tv_sec = 0;
tout_val.it_value.tv_usec = 100000; /* 100000 timer */
/* ... and every 100 msec after that. */
tout_val.it_interval.tv_sec = 0 ;
tout_val.it_interval.tv_usec = 100000;
checkOCIDs();
setitimer(ITIMER_REAL, &tout_val,0);
return ;
}
Function TimeOut_CallBack ( ) is called only once and then on checkOCIDs( ) function must be executed after a wait of 100ms continuously.
Currently, The application is going for a block as checkOCIDs( ) function takes more than 100ms of time to complete and before that the Timer Out is triggered.
I do not wish to use while(1) with sleep( ) / usleep( ) as it eats up my CPU enormously.
Please suggest a alternative to achieve my requirement.
It is not clear whether the "check" function should be executed while it is in progress and timer expires. Maybe it would be ok to you to introduce variable to indicate that timer expired and your function should be executed again after it completes, pseudo-code:
static volatile bool check_in_progress = false;
static volatile bool timer_expired = false;
void TimeOut_CallBack(int w)
{
// ...
if (check_in_progress) {
timer_expired = true;
return;
}
// spawn/resume check function thread
// ...
}
void checkThreadProc()
{
check_in_progress = true;
do {
timer_expired = false;
checkOCIDs();
} while(timer_expired);
check_in_progress = false;
// end thread or wait for a signal to resume
}
Note, that additional synchronization may be required to avoid race conditions (for instance when one thread exists do-while loop and check_in_progress is still set and the other sets timer_expired, check function will not be executed), but that's depends on your requirements details.