简体   繁体   English

避免竞争条件性能

[英]Avoid race condition performance

I have two asynchronous threads (explicitly asked to do it that way) running 2 different methods from an object, move_robot() and get_area() .我有两个异步线程(明确要求这样做)从 object、 move_robot()get_area() ) 运行 2 种不同的方法。 The first method moves a vehicle through different positions and the second one calculates the area covered thus far.第一种方法使车辆移动通过不同的位置,第二种方法计算到目前为止所覆盖的区域。 Both share two object attributes:两者共享两个 object 属性:

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 .get_area()方法中,我锁定以将this->position属性保存在变量中,并在整个迭代中具有相同的属性并初始化第一个previous_measure In next_step() is used when this->position changes according the dynamics of the vehicle.this->position根据车辆的动态变化时,在next_step()中使用。

Moreover, how would you lock the moving attribute inside the while condition?此外,您如何将moving属性锁定在 while 条件中? 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.以及如何避免这种情况:我执行get_area() ,机器人移动并结束路径,我离开get_area方法而不进行最后一次迭代。

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).我的问题是是否可以优化这种锁定和解锁,因为它经常进行(我不想设置生产者-客户端结构,因为我希望 get_area() 独立运行)。


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但不知道有没有更干净的东西

Optimization #1: assuming the speed of the robot is slow compared to the speed of computation优化#1:假设机器人的速度比计算速度慢

Considering the speed of the robot, there is no real need to lock both the position and moving since the rate of change of this values, compared to the rate of computation will be enormously small, so the margin of error due to stale read will be negligible.考虑到机器人的速度,实际上并没有必要同时锁定positionmoving ,因为这个值的变化率与计算速度相比将非常小,因此由于stale读取导致的误差范围将是微不足道。

In any case the above code is doing exactly that, since the previous_measure = this->position is reading the position while it's unlocked, therefore there is small chance that previous_measure != auxiliar at the end of the loop.在任何情况下,上面的代码都是这样做的,因为previous_measure = this->positionposition解锁时读取它,因此在循环结束时previous_measure != auxiliar的可能性很小。

To assure that a final read is executed (meaning get_area is computed again after moving is false), we can repeat the calculation once more after leaving the loop, since then the robot had stoped moving and the position will never change.为了确保执行最终读取(意味着get_areamoving为假后再次计算),我们可以在离开循环后再次重复计算,因为那时机器人已经停止移动并且 position 永远不会改变。

Optimization #2: Consumer-Producer communication trough Ring Buffer优化#2:消费者-生产者通过 Ring Buffer 进行通信

In case the speed of change of the variables is close to the speed of computiation, the optimization #1 will obviously create significant error.如果变量的变化速度接近计算速度,优化#1显然会产生很大的误差。 In such case, you can consider using ring buffer to move the values from move_robot to get_area without locking.在这种情况下,您可以考虑使用环形缓冲区将值从move_robot移动到get_area而无需锁定。 If you have only one consumer and only one producer thread, there is no need to lock.如果你只有一个消费者,只有一个生产者线程,则不需要加锁。 Here is an example of implementation of ring buffer (or circular buffer). 是一个实现环形缓冲区(或循环缓冲区)的示例。

In the first example you're reading this->moving while not holding the lock.在第一个示例中,您正在阅读this->moving而没有持有锁。 This will lead to UB if another thread is also writing it.如果另一个线程也在编写它,这将导致 UB。 You can reorder the locking a bit to make it correct, for example like this:您可以重新排序锁定以使其正确,例如:

   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
        while (this->moving) {
            auto auxiliar = this->position;
            this->area_covered += distance(auxiliar , previous_measure) * this->width;
            previous_measure = this->position; // save the new position for the next iteration
            lck.unlock();
            this_thread::sleep_for(chrono::milliseconds(10)); // sleep for 10 ms
            std::cout << "Area:" << this->area_covered << " m²" << std::endl;
            lck.lock();
        }
    }

Also, move_robot must also hold the lock while updating shared values.此外, move_robot在更新共享值时也必须持有锁。 Just make sure to not hold the lock while sleeping.只要确保在睡觉时不要握住锁。

    void move_robot(const vector<vector<double> > &map) {
        std::unique_lock<std::mutex> lck(mtx);
        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();
                lck.unlock();
                this_thread::sleep_for(chrono::milliseconds(10)); // sleep for 10 ms
                lck.lock();
            }
        }
        this->moving = false; // notify get area to leave
    }

Remember, if writing is involved, then all parallel access to a variable must either be protected by a mutex or the variable must be made atomic .请记住,如果涉及写入,则对变量的所有并行访问都必须受到互斥锁的保护,或者必须使变量成为atomic

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用std :: mutex避免竞争条件 - Avoid race condition using std::mutex 避免在C#程序中出现这种竞争情况 - Avoid this race condition in C# program 如何避免VxWorks中条件变量中的竞争条件 - How to avoid race conditions in a condition variable in VxWorks 具有性能计数器的当前条件的竞争状况 - Race condition with Performance Counters for current process 避免Android本机代码中的竞争条件(C ++) - avoid race condition in android native code (C++) 在没有互斥锁的情况下引用计数时如何避免竞争条件? - How to avoid race condition when refcounting without a mutex? 在C ++上的ManualResetEvent(来自C#)实现:如何避免竞争情况 - ManualResetEvent (from C#) implementation on C++: how to avoid race condition 避免在统计信息和重命名之间出现TOCTOU(检查时间,使用时间)竞争情况 - Avoid TOCTOU (time-of-check, time-of-use) race condition between stat and rename c + +尝试添加Peterson算法以避免共享内存中的竞争条件 - c++ trying to add Peterson algorithm to avoid race condition in shared memory C++:如何在不使用锁的情况下比较 2 个 integer 变量时避免竞争条件 - C++ : How to avoid a race condition when comparing 2 integer variables without using a lock
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM