Fix some concurrency issues causing unreliability

This commit is contained in:
2026-02-28 22:36:54 -05:00
parent 9066ccd721
commit 657dc42833
2 changed files with 37 additions and 30 deletions

View File

@@ -30,7 +30,11 @@ LIB_API void cleanup() {
LIB_API int send_angle_control(int module_id, int angle) { LIB_API int send_angle_control(int module_id, int angle) {
if (const auto maybe_module = robot_controller->getModule(module_id)) { if (const auto maybe_module = robot_controller->getModule(module_id)) {
const auto module = (*maybe_module).lock(); const auto module = (*maybe_module).lock();
module->actuate(angle); if (module) {
module->actuate(angle);
} else {
spdlog::warn("[c_control] send_angle_control: module {} has expired", module_id);
}
} }
return 0; return 0;
} }

View File

@@ -35,11 +35,16 @@ using namespace std::chrono_literals;
RobotController::~RobotController() { RobotController::~RobotController() {
m_stop_thread = true; m_stop_thread = true;
m_metadata_loop.join(); if (m_metadata_loop.joinable())
m_transmit_loop.join(); m_metadata_loop.join();
m_configuration_loop.join(); if (m_transmit_loop.joinable())
m_sensor_loop.join(); m_transmit_loop.join();
m_expiry_looop.join(); if (m_configuration_loop.joinable())
m_configuration_loop.join();
if (m_sensor_loop.joinable())
m_sensor_loop.join();
if (m_expiry_looop.joinable())
m_expiry_looop.join();
} }
std::vector<std::weak_ptr<Module>> RobotController::getModules() { std::vector<std::weak_ptr<Module>> RobotController::getModules() {
@@ -85,15 +90,17 @@ std::optional<std::weak_ptr<Module>> RobotController::getModule(uint8_t device_i
void RobotController::resetModules() { void RobotController::resetModules() {
std::unique_lock module_lock(m_module_lock); std::unique_lock module_lock(m_module_lock);
std::unique_lock conn_lock(m_connection_lock); std::unique_lock conn_lock(m_connection_lock);
m_id_to_module.erase(m_id_to_module.begin(), m_id_to_module.end()); m_id_to_module.clear();
m_connection_map.erase(m_connection_map.begin(), m_connection_map.end()); m_connection_map.clear();
} }
void RobotController::fetchDirectlyConnectedModules(bool block) { void RobotController::fetchDirectlyConnectedModules(bool block) {
spdlog::info("[Control] Fetching modules from network"); spdlog::info("[Control] Fetching modules from network");
auto t = std::thread([&] { // Capture m_messaging_interface by value (shared_ptr) so the detached
auto out = m_messaging_interface->find_connected_modules( // thread does not hold a dangling reference to 'this'.
std::chrono::milliseconds(SCAN_DURATION_MS)); auto messaging = m_messaging_interface;
auto t = std::thread([messaging] {
auto out = messaging->find_connected_modules(std::chrono::milliseconds(SCAN_DURATION_MS));
spdlog::info("[Control] Found {} modules on the network", out.size()); spdlog::info("[Control] Found {} modules on the network", out.size());
}); });
@@ -189,25 +196,21 @@ void RobotController::expiry_loop() {
} }
} }
// todo // Remove connections involving expired modules.
// Remove connections for (auto it = m_connection_map.begin(); it != m_connection_map.end();) {
// for (auto it = m_connection_map.begin(); it != m_connection_map.end();) { if (delete_modules.contains(it->first)) {
// // Remove it->x connections it = m_connection_map.erase(it);
// if (delete_modules.contains(it->first)) { } else {
// it = m_connection_map.erase(it); // Remove individual connections pointing to an expired module.
// } else { auto &conns = it->second;
// ++it; conns.erase(std::remove_if(conns.begin(), conns.end(),
// } [&](const Flatbuffers::ModuleConnectionInstance &c) {
return delete_modules.contains(c.to_module_id);
// // Remove x->it connections }),
// for (auto it2 = it->second.begin(); it2 != it->second.end();) { conns.end());
// if (delete_modules.contains(it2->to_module_id)) { ++it;
// it2 = it->second.erase(it2); }
// } else { }
// ++it2;
// }
// }
// }
} }
} }