I have two asynchronous threads (explicitly asked to do it that way) running 2 different methods from an object, move_robot()
and get_area()
. The first method moves a vehicle through different positions and the second one calculates the area covered thus far. Both share two object attributes:
vector<double> position; // saves current position of the vehicle
bool moving; // true if the vehicle has not reach the end of the path
In order to avoid race conditions I am using locks the following way:
void get_area() {
std::unique_lock<std::mutex> lck(mtx); // get mutex
static vector<double> previous_measure = this->position; // initialized with the first position the robot is in
lck.unlock();
while (this->moving) {
lck.lock();
auto auxiliar = this->position;
lck.unlock();
this->area_covered += distance(auxiliar , previous_measure) * this->width;
previous_measure = this->position; // save the new position for the next iteration
this_thread::sleep_for(chrono::milliseconds(10)); // sleep for 10 ms
std::cout << "Area:" << this->area_covered << " m²" << std::endl;
}
}
void next_step() {
std::unique_lock<std::mutex> lck(mtx); // get mutex
this->position[0] += DT * this->direction[0];
this->position[1] += DT * this->direction[1];
}
void move_robot(const vector<vector<double> > &map) {
// accumulate the footprint while the robot moves
// Iterate through the path
for (unsigned int i=1; i < map.size(); i++) {
while (distance(position , map[i]) > DISTANCE_TOLERANCE ) {
this->direction = unitary_vector(map[i], this->position);
this->next_step();
this_thread::sleep_for(chrono::milliseconds(10)); // sleep for 10 ms
}
}
this->moving = false; // notify get area to leave
}
In the get_area()
method I am locking to save the this->position
attribute in a variable and have the same one over the whole iteration and to initialize the first previous_measure
. In next_step()
is used when this->position
changes according the dynamics of the vehicle.
Moreover, how would you lock the moving
attribute inside the while condition? And how to avoid this situation: I execute get_area()
, the robot moves and ends the path and I leave the get_area
method without doing the last iteration.
My question is whether it would be possible to optimize this locking and unlocking, as it is done pretty often (I do not want to set a producer-client structure because I want get_area() to run independent).
EDIT:
I have changed the condition in the while to:
bool is_moving() {
std::unique_lock<std::mutex> lck(mtx);
return moving;
}
void get_area() {
std::unique_lock<std::mutex> lck(mtx);
static vector<double> previous_measure = this->position;
lck.unlock();
while (this->is_moving()) {...}
}
But do not know if there is something even cleaner