c++ - 两个线程共享变量

标签 c++ multithreading mutex ros

我正在编写一个带有两个线程的ros节点,以支持C++中的客户端动态重新配置。一个线程负责订阅 float 主题/error,获取sum_of_error值的总和,并递增batch_size。如果 batch_size 达到 BATCH,另一个线程负责取平均值,然后将 sum_of_errorbatch_size 重置为0. batch_sizesum_of_error 都是两个线程之间的共享变量,因此我使用互斥体来防止数据竞争。用于订阅主题的线程运行良好,但用于获取平均值并重置 batch_sizesum_of_error 的线程卡住了。我注意到该过程陷入了函数 get_value() 中的 while 循环。我认为这与竞争条件有关。任何想法?我该如何更改代码来解决这个问题。

#include <ros/ros.h>
#include <string>
#include <vector>
#include <std_msgs/Float32.h>
#include <dynamic_reconfigure/client.h>
#include <calibration/HcNodeConfig.h>
#include <mutex>
#include <thread>

using namespace std;


mutex m;
int batch_size = 0;
float sum_of_error = 0;

int BATCH = 10;


float get_value() {
    while (batch_size < BATCH) {
    }
    float res = sum_of_error / batch_size;
    m.lock();
    sum_of_error = 0.0;
    batch_size = 0;
    m.unlock();
    return res;
}


void adjuster_callback(const hc::HcNodeConfig& data) {
    
}


void listener_callback(const std_msgs::Float32ConstPtr& msg) {
    float current_error = msg->data;
    m.lock();
    batch_size++;
    sum_of_error += current_error;
    m.unlock();
}


void start_listener(ros::NodeHandle n) {
    ros::Subscriber listener;
    ros::Rate loop_rate(BATCH);
    listener = n.subscribe("/error", BATCH, listener_callback);
    while (ros::ok()) {
        ros::spinOnce();
        loop_rate.sleep();
    }
}


void start_adjuster(ros::NodeHandle n) {
    ros::Rate loop_rate(BATCH);
    hc::HcNodeConfig config;
    dynamic_reconfigure::Client<hc::HcNodeConfig> client("/lidar_front_left_hc", adjuster_callback);
    ros::Duration d(2);
    client.getDefaultConfiguration(config, d);
    while (ros::ok()) {
        float current_error = get_value();
        if (current_error > 0.0) {
             config.angle = 0.0;
             client.setConfiguration(config);
        }
        ros::spinOnce();
        loop_rate.sleep();
    }
}


int main(int argc, char ** argv) {
    ros::init(argc, argv, "adjuster");
    ros::NodeHandle n;

    thread t1(start_listener, n);
    thread t2(start_adjuster, n);

    t1.join();
    t2.join();
    return 0;
}

最佳答案

    while (batch_size < BATCH) {
    }

这样做的明显目的是等待另一个执行线程增加 batch_size 直到达到 BATCH

但是,由于对 batch_size 的访问根本不同步,因此会导致未定义的行为。

其他执行线程使用互斥体同步对 batch_size 的修改。该执行线程必须执行相同的操作。像这样的事情:

int get_batch_size()
{
    m.lock();

    int s=batch_size;

    m.unlock();

    return s;
}

// ...

while (get_batch_size() < BATCH)
   ;

这当然是繁忙轮询,效率极低。应将条件变量与此互斥体一起使用,以获得最佳性能和结果。

关于c++ - 两个线程共享变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73000611/

相关文章:

java - 等待/通知死锁

c++ - 需要高级低级编程的书籍和网站建议

c++ - 将 int 值写入字节数组

.net - 多线程是适合我的情况的正确方法吗?

go - 在 Go 的结构体中使用互斥锁

iOS - 线程安全和performSelectorOnMainThread

c - Reader - Writer 互斥体

C++11 通过原始指针或引用获取 unique_ptr 的所有权?

java - C++ vs Java 速度(带算术的循环)

c++ - 理解 std::thread 语义,工作函数作为类成员