"printf" appears to be non-deterministic in Qt? - c++

I know "printf" is standard-c and should be deterministic. But when run in Qt I see a more non-deterministic response(clock cycles). Could this be due to Qt adding some "pork" to its response?
I have multiple threads that make call to function that uses a mutex. When one thread enters it set a switch so the others can't until it is done. Things appeared to work ok for acouple seconds and then threads appeared to be killed off from 10 to 1 thread. So I tried adding a delay: (k=k+1: no help), then (looping k=k+1: no help), (usleep works), and so does (printf) work at creating a random delay and allowing all threads to continue running.
void CCB::Write(int iThread)
{
static bool bUse = false;
bool bDone = false;
char cStr[20];
int posWrite;// = *m_posWrite; // issue of posWrite be altered with next extrance
long k = 0;
long m = 0;
m_threadCount++;
while(bDone == false){
if(bUse == false){
bUse = true;
posWrite = *m_posWrite;
memcpy(m_cmMessageCB + posWrite, &m_cmMessageWrite, sizeof(typeCanMessage));
memset(cStr, '\0', 20);
memcpy(cStr, (m_cmMessageCB + posWrite)->cMessage, 11); //fails: every 20
*m_posWrite = *m_posWrite + 1;
if(*m_posWrite == m_iNBufferLength)
*m_posWrite = 0;
bDone = true;
bUse = false;
}else if(bUse == true){
//why are threads being killed ?
// printf("T%d_%d ", iThread, m_threadCount);//non-deterministic value ?
usleep(1);//non-deterministic value
//k++;//delay of a couple clock cycles was not enough
/*
for(k = 0; k < iThread * 100; k++){//deterministic and fails to resolve thread problem
m++;
}
*/
}
}
}

Related

Global variable doesn't update prior to next loop

I'm trying to build a tachometer in C++ for my ESP32. When I uncomment Serial.printf("outside rev: %d \n", rev); outside of the conditional it works, but when I comment it I get values that are orders of magnitude greater than they should be (700 revolutions without, vs 7 revolutions with). My best guess is that the print statement is slowing the loop() down just enough for incrementRevolutions() to toggle the global variable passedMagnet from true to false before the next loop. That would make sense, since a delay in updating passedMagnet would allow newRevCount++; to be triggered multiple times. But this is obviously something I can't debug with either print statements or step-through debugging given the time-sensitive nature of the race condition.
bool passedMagnet = true;
int incrementRevolutions(int runningRevCount, bool passingMagnet)
{
// Serial.printf("passedMagnet: %d , passingMagnet %d , runningRevCount: %d \n", passedMagnet, passingMagnet, runningRevCount);
int newRevCount = runningRevCount;
if (passedMagnet && passingMagnet)
{ //Started a new pass of the magnet
passedMagnet = false;
newRevCount++;
}
else if (!passedMagnet && !passingMagnet)
{ //The new pass of the magnet is complete
passedMagnet = true;
}
return newRevCount;
}
unsigned long elapsedTime = 0;
unsigned long intervalTime = 0;
int rev = 0;
void loop()
{
intervalTime = millis() - elapsedTime;
rev = incrementRevolutions(rev, digitalRead(digitalPin));
// Serial.printf("outside rev: %d \n", rev);
if (intervalTime > 1000)
{
Serial.printf("rev: %d \n", rev);
rev = 0;
elapsedTime = millis();
}
}
Is this a known gotcha with Arduino or C++ programming? What should I do to fix it?
I think the test is to blame. I had to rename and move things a bit to visualize the logic, sorry about that.
bool magStateOld = false; // initialize to digitalRead(digitalPin) in setup()
int incrementRevolutions(int runningRevCount, bool magState)
{
int newRevCount = runningRevCount;
// detect positive edge.
if (magState && !magStateOld) // <- was eq. to if (magState && magStateOld)
// the large counts came from here.
{
newRevCount++;
}
magStateOld = magState; // record last state unconditionally
return newRevCount;
}
You could also write it as...
int incrementRevolutions(int n, bool magState)
{
n += (magState && !magStateOld);
magStateOld = magState;
return n;
}
But the most economical (and fastest) way of doing what you want would be:
bool magStateOld;
inline bool positiveEdge(bool state, bool& oldState)
{
bool result = (state && !oldState);
oldState = state;
return result;
}
void setup()
{
// ...
magStateOld = digitalRead(digitalPin);
}
void loop()
{
// ...
rev += (int)positiveEdge(digitalRead(digitalPin), magStateOld);
// ...
}
It's reusable, and saves both stack space and unnecessary assignments.
If you cannot get clean transitions from your sensor (noise on positive and negative edges, you'll need to debounce the signal a bit, using a timer.
Example:
constexpr byte debounce_delay = 50; // ms, you may want to play with
// this value, smaller is better.
// but must be high enough to
// avoid issues on expected
// RPM range.
// 50 ms is on the high side.
byte debounce_timestamp; // byte is large enough for delays
// up to 255ms.
// ...
void loop()
{
// ...
byte now = (byte)millis();
if (now - debounce_timestamp >= debounce_delay)
{
debounce_timestamp = now;
rev += (int)positiveEdge(digitalRead(digitalPin), magStateOld);
}
// ...
}

My game of Snake crashes when you eat an apple, and the apple spawns inside your body after picking a new position (C++, SDL)

I thought I'd attempt to make Snake since it is a pretty easy game to make. I was having an issue where the apple would spawn inside the snakes body, and so I came up with a way to prevent that from happening:
void getRandomApplePos() {
// variable that tells the while loop whether the moving of the apple was successful
bool success;
// variable that is set to false if the apple is inside the snakes body
bool appleNotInside;
// Tells the collision to stop testing for collision until the apple has successfully moved
bool appleHasMoved;
// sets the variables
success = false;
appleNotInside = false;
appleHasMoved = false;
// while the apple spawns inside the snake, it keeps generating new positions
while (!success) {
// random seed
srand((unsigned int)time(NULL));
// gets a random position
int randomX = rand() % 769;
int randomY = rand() % 673;
// resets the two variables if this while loop as ran again
apple.delta_pos_x = 0;
apple.delta_pos_y = 0;
// checks to see if the apple has spawned in the same exact position
while (apple.delta_pos_x == 0 && apple.delta_pos_y == 0) {
// gets the previous poition of the apple
apple.prevPos_x = apple.x;
apple.prevPos_y = apple.y;
// picks a new apple position
apple.x = round((randomX) / 32) * 32;
apple.y = round((randomY) / 32) * 32;
// gets the new apple position
apple.currentPos_x = apple.x;
apple.currentPos_y = apple.y;
// sets the difference between the positions, if it's 0, then it has spawned in the same exact location
apple.delta_pos_x = (float)(apple.currentPos_x - apple.prevPos_x);
apple.delta_pos_y = (float)(apple.currentPos_y - apple.prevPos_y);
}
// checks to see if the snake length is only one, as to make the list not go out of index
if (snake.bodyLength == 1) {
// if the apple happens to spawn inside the snake with a length of 1, it will add false to the appleInSnake vector, else it adds true
if (apple.x == snakeBody[0][0] && apple.y == snakeBody[0][1]) {
appleNotInside = false;
appleInSnake.push_back(appleNotInside);
}
else {
appleNotInside = true;
appleInSnake.push_back(appleNotInside);
}
}
else {
// if the apple happens to spawn inside the currently compared snakeBodyPosition, it will add false to the appleInSnake vector, else it adds true
for (int i = 0; i < snakeBody.size(); i++) {
if (apple.x == snakeBody[i][0] && apple.y == snakeBody[i][1]){
appleNotInside = false;
appleInSnake.push_back(appleNotInside);
}
else {
appleNotInside = true;
appleInSnake.push_back(appleNotInside);
}
}
}
// if false appears inside the appleInSnake vector at all, it sets success to false and goes through the loop again. Else it breaks out.
if (std::find(appleInSnake.begin(), appleInSnake.end(), false) != appleInSnake.end()) {
success = false;
}
else {
success = true;
}
//clears appleInSnake so that it can take in a new comparision
appleInSnake.clear();
}
// tells the collision to start back up again
appleHasMoved = true;
}
So, whenever the apple does end up spawning inside of the snakes body, it crashes, just outright. I suspect some kind of infinite loop, but I can't put my finger on why this happens.
You are initializing your random number generator within your loop.
Note that the RNG is deterministic. It means that you will end up drawing the same numbers all over again as in the previous loop.
Initialize the RNG once at the start of your program. This way, the numbers drawn may be expected to be different within every loop.
You might wonder, that the crude use of time() should prevent this. A typical implementation of time() will have the granularity of seconds. So you would only expect the return value to change once a second, hence, you get the same initialization over and over again in your loop.

More efficient way for reading CAN data in while loop

I have 3 devices which send 8 bytes of data over CAN interface. To read the buffer from CAN I am using a while loop which looks something like this:
void CanServer::ReadFromCAN() {
data_from_buffer_.clear();
can_frame frame;
read_can_port_ = read(soc_, &frame, sizeof(struct can_frame));
if (read_can_port_ < 0) return;
id_ = frame.can_id&0x1FFFFFFF;
dlc_ = frame.can_dlc;
for (const auto& byte : frame.data)
data_from_buffer_.push_back(byte);
}
while (ros::ok()) {
std_msgs::Int32MultiArray tachometer_array;
std::vector<__u8> data_from_can;
/***
* Read for the Radar1
*/
this->ReadFromCAN();
if (read_can_port_ < 0) continue;
//ROS_INFO("Read from CAN");
if (id_ == can_id::RadarFrame1)
for (int i = 0; i < dlc_; i++) {
radar1_bytes_[i] = data_from_buffer_[i];
radar1_buffer_.push_back(data_from_buffer_[i]);
}
if (IsMagicWord(radar1_bytes_, 0)) {
frame_id = "radar1_link";
this->PulbishRadarPCL(frame_id, radar1_pub_, radar1_buffer_, 0);
radar1_buffer_.clear();
canFrame_.can_dlc = 0;
}
}
if (id_ == can_id::RadarFrame2) {
for (int i = 0; i < dlc_; i++) {
radar2_bytes_[i] = data_from_buffer_[i];
radar2_buffer_.push_back(data_from_buffer_[i]);
}
if (IsMagicWord(radar2_bytes_, 1)) {
frame_id = "radar2_link";
this->PulbishRadarPCL(frame_id, radar2_pub_, radar2_buffer_, 1);
radar2_buffer_.clear();
canFrame_.can_dlc = 0;
}
}
if (id_ == can_id::RadarFrame3) {
for (int i = 0; i < dlc_; i++) {
radar3_bytes_[i] = data_from_buffer_[i];
radar3_buffer_.push_back(data_from_buffer_[i]);
}
if (IsMagicWord(radar3_bytes_, 2)) {
frame_id = "radar3_link";
this->PulbishRadarPCL(frame_id, radar3_pub_, radar3_buffer_, 2);
radar3_buffer_.clear();
canFrame_.can_dlc = 0;
}
}
rate.sleep();
}
Where rate.sleep() is similar to sleep() function in C++.
Right now, I am running this while loop in 5 MHz however I think this is an overkill and I am getting almost 100% CPU usage on a 1 core.
I tried to play around with the delay time but I think this is highly inefficient and I wonder is there any other way to handle this?
It turns out that poll is what you need. Here is my example.
First, create a pollfd structure from <poll.h> header in Linux. I have decided to create a class member but you can create however you like:
pollfd poll_;
poll_.fd = soc_;
poll_.events = POLLIN;
poll_.revents = 0;
Here, soc_ is a socket and POLLIN means that you want to read from the socket.
Then, in my while loop, instead of delaying I just used this function at the beginning of my while loop:
poll_int = poll(&poll_, 1, 100);
if (poll_int <= 0) continue;
So poll() function returns value of 1 if the read was succesful and I made a timeout of 100ms (just a random number, I know that the data are coming at much higher rate)
With that, you will only read the data from socket whenever poll returns a value greater that 0.
Results? 3% CPU usage and if you want to add more data into your socket flow, poll will optimize for you so this is a scalable way of reading something like CAN bus.

Fastest and safest way to call functions in extern process

Describtion of the problem:
we need to call a function in extern process as fast as possible. Boost interprocess shared memory is used for communication. The extern process is either mpi master or a single executable. The calculation time of the function lies between 1ms and 1s. The function should be called up to 10^8-10^9 times.
I've tried a lot of possibilities, but I still have some problems with each of them. Here I introduce two of best working implementations
Version 1 ( using intreprocess conditions )
Main-process
bool calculate(double& result, std::vector<double> c){
// data_ptr is a structure in shared memoty
data_ptr_->validCalculation = false;
bool timeout = false;
// write data (cVec_ is a vector in shared memory )
cVec_->clear();
for (int i = 0; i < c.size(); ++i)
{
cVec_->push_back(c[i]);
}
// cond_input_data is boost interprocess condition
data_ptr_->cond_input_data.notify_one();
boost::system_time const waittime = boost::get_system_time() + boost::posix_time::seconds(maxWaitTime_in_sec);
// lock slave process
scoped_lock<interprocess_mutex> lock_output(data_ptr_->mutex_output);
// wait till data calculated
timeout = !(data_ptr_->cond_output_data.timed_wait(lock_output, waittime)); // true if timeout, false if no timeout
if (!timeout)
{
// get result
result = *result_;
return data_ptr_->validCalculation;
}
else
{
return false;
}
};
Extern process runs a while-loop ( till abort condition is fullfilled)
do {
scoped_lock<interprocess_mutex> lock_input(data_ptr_->mutex_input);
boost::system_time const waittime = boost::get_system_time() + boost::posix_time::seconds(maxWaitTime_in_sec);
timeout = !(data_ptr_->cond_input_data.timed_wait(lock_input, waittime)); // true if timeout, false if no timeout
if (!timeout)
{
if (!*abort_flag_) {
c.clear();
for (int i = 0; i < (*cVec_).size(); ++i) //Insert data in the vector
{
c.push_back(cVec_->at(i));
}
// calculate value
if (call_of_function_here(result, c)) { // valid calculation ?
*result_ = result;
data_ptr_->validCalculation = true;
}
}
}
//Notify the other process that the data is avalible or we dont get the input data
data_ptr_->cond_output_data.notify_one();
} while (!*abort_flag_); // while abort flag is not set, check if some values should be calculated
This is best working version, but sometimes it holds up, if the calculation time is short (~1ms). I assume, it happens, if main-process reaches
data_ptr_->cond_input_data.notify_one();
earlier, than extern process is waiting on
timeout = !(data_ptr_->cond_input_data.timed_wait(lock_input, waittime));
waiting condition. So we have probably some kind of synchronisation problem.
Second condition does not help ( i.e. wait only if input data not set, similar to the anonymous condition example with message_in flag). Since, it is still possible, that one process notify the other one, before the second one is waiting for notification.
Version 2 ( using boolean flag and while loop with some delay )
Main-process
bool calculate(double& result, std::vector<double> c){
data_ptr_->validCalculation = false;
bool timeout = false;
// write data
cVec_->clear();
for (int i = 0; i < c.size(); ++i) //Insert data in the vector
{
cVec_->push_back(c[i]);
}
// this is the flag in shared memory used for communication
*calc_flag_ = true;
clock_t test_begin = clock();
clock_t calc_time_begin = clock();
do
{
calc_time_begin = clock();
boost::this_thread::sleep(boost::posix_time::milliseconds(while_loop_delay_m_s));
// wait till data calculated
timeout = (double(calc_time_begin - test_begin) / CLOCKS_PER_SEC > maxWaitTime_in_sec);
} while (*(calc_flag_) && !timeout);
if (!timeout)
{
// get result
result = *result_;
return data_ptr_->validCalculation;
}
else
{
return false;
}
};
and the extern process
do {
// we wait till input data is set
wait_begin = clock();
do
{
wait_end = clock();
timeout = (double(wait_end - wait_begin) / CLOCKS_PER_SEC > maxWaitTime_in_sec);
boost::this_thread::sleep(boost::posix_time::milliseconds(while_loop_delay_m_s));
} while (!(*calc_flag_) && !(*abort_flag_) && !timeout);
if (!timeout)
{
if (!*abort_flag_) {
c.clear();
for (int i = 0; i < (*cVec_).size(); ++i) //Insert data in the vector
{
c.push_back(cVec_->at(i));
}
// calculate value
if (call_of_local_function(result, c)) { // valid calculation ?
*result_ = result;
data_ptr_->validCalculation = true;
}
}
}
//Notify the other process that the data is avalible or we dont get the input data
*calc_flag_ = false;
} while (!*abort_flag_); // while abort flag is not set, check if some values should be calculated
The problem in this version is the delay-time. Since we have calculation times close to 1ms, we have to set the delay at least to this value. For smaller delays the cpu-load is high, for higher delays we lose a lot of performance due to not necessary waiting time
Do you have an idea how to improve one of this versions? or may be there is a better solution?
thx.

C++ Debug assertion failed, using Windows.h mutex

I have a problem caused by this code:
char KernelFS::mount(Partition* part) {
WaitForSingleObject(mutexFS,INFINITE);
int pos;
for(pos=0; pos<26; pos++)
if(mountedPartitions[pos] == 0)
break;
if(pos < 26) {
mountedPartitions[pos] = part;
bitVectors[pos] = new BitVector(part);
fileEvidention[pos] = new ListHandler();
openedFiles[pos] = 0;
forbidOpening[pos] = false;
ReleaseMutex(mutexFS);
return intToChar(pos);
}
else {
ReleaseMutex(mutexFS);
return '0';
}
}
and
char KernelFS::format(char part){
WaitForSingleObject(mutexFS,INFINITE);
forbidOpening[charToInt(part)] = true;
ReleaseMutex(mutexFS);
while(openedFiles[charToInt(part)]>0)
WaitForSingleObject(unmountSem,INFINITE);
WaitForSingleObject(mutexFS,INFINITE);
// write fresh bit vector to cluster 0 of partition
bitVectors[charToInt(part)]->formatBitVector();
openedFiles[charToInt(part)] = 0;
forbidOpening[charToInt(part)] = false;
delete fileEvidention; //!!***!!
fileEvidention[charToInt(part)] = new ListHandler();
// some other stuff, irrelevant
ReleaseMutex(mutexFS);
return 1;
}
There are 3 thread executing, 1 is blocked and two are running through this code;
they first call mount, then format (each has its own argument Partition object, p1 and p2).
The first time mount is called, it always goes through - then there is an assertion failure at random during one of the next calls of mount/format by any of the two running threads.
Usually, it fails during thread 1 - it calls mount(..) completes it, then calls format(...) and fails around:
delete fileEvidention[charToInt(pos)];
(in debug mode, when I reach this instruction, even if I try to go into with F11, there is an assertion failure)
In case it matters... this is the initialization:
char KernelFS::firstLetter = 'A'; // 'A' = 65
Partition* KernelFS::mountedPartitions[26] = {0}; // init. no partitions are mounted
BitVector* KernelFS::bitVectors[26] = {0}; // init. no partitions are mounted
bool KernelFS::forbidOpening[26] = {false};
long KernelFS::openedFiles[26] = {0};
ListHandler* KernelFS::fileEvidention[26] = {0};
HANDLE KernelFS::mutexFS = CreateMutex(0,0,0);
HANDLE KernelFS::unmountSem = CreateSemaphore(0,0,INFINITE,0);
I have never had this error before, I have no idea how to debug this nor what could cause it.
Thanks for the help, in advance.
EDIT:
when i remove the marked line of code (and ignore the memory leak) there is no assertion failure. What is this witchcraft ?
! :)
Solved. should be
delete fileEvidention[charToInt(part)];
......