我正在编写一个带有两个线程的ros节点,以支持C++中的客户端动态重新配置。一个线程负责订阅 float 主题/error
,获取sum_of_error
值的总和,并递增batch_size
。如果 batch_size
达到 BATCH
,另一个线程负责取平均值,然后将 sum_of_error
和 batch_size
重置为0. batch_size
和 sum_of_error
都是两个线程之间的共享变量,因此我使用互斥体来防止数据竞争。用于订阅主题的线程运行良好,但用于获取平均值并重置 batch_size
和 sum_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/