ros2 runtime_error ai_generated true

rclcpp: Deadlock detected: callback waiting for another callback in same MutuallyExclusiveCallbackGroup

ID: ros2/rclcpp-dual-mode-callback-group-deadlock

Also available as: JSON · Markdown · 中文
85%Fix Rate
90%Confidence
1Evidence
2024-01-10First Seen

Version Compatibility

VersionStatusIntroducedDeprecatedNotes
ROS2 Humble (rclcpp 16.0.0) active
ROS2 Iron (rclcpp 17.0.0) active
ROS2 Rolling (rclcpp 18.0.0) active

Root Cause

A callback in a MutuallyExclusiveCallbackGroup is blocking on a service or action call that requires another callback in the same group, causing a deadlock because the group only allows one callback at a time.

generic

中文

互斥回调组中的某个回调阻塞在需要同一组中另一个回调的服务或动作调用上,导致死锁,因为该组一次只允许一个回调执行。

Official Documentation

https://docs.ros2.org/latest/api/rclcpp/classrclcpp_1_1CallbackGroup.html

Workarounds

  1. 90% success Move the blocking service call to a separate callback group (e.g., a ReentrantCallbackGroup) so it does not block the original group: auto callback_group = this->create_callback_group(rclcpp::CallbackGroupType::Reentrant);
    Move the blocking service call to a separate callback group (e.g., a ReentrantCallbackGroup) so it does not block the original group: auto callback_group = this->create_callback_group(rclcpp::CallbackGroupType::Reentrant);
  2. 85% success Use async service clients to avoid blocking the callback entirely: auto future = client->async_send_request(request);
    Use async service clients to avoid blocking the callback entirely: auto future = client->async_send_request(request);

中文步骤

  1. 将阻塞的服务调用移动到单独的回调组(例如ReentrantCallbackGroup),使其不会阻塞原始组:auto callback_group = this->create_callback_group(rclcpp::CallbackGroupType::Reentrant);
  2. 使用异步服务客户端以避免完全阻塞回调:auto future = client->async_send_request(request);

Dead Ends

Common approaches that don't work:

  1. Increase the callback group's thread count or use a ReentrantCallbackGroup 60% fail

    Reentrant allows concurrent execution but does not solve the logical dependency; the service call still blocks.

  2. Add a sleep or yield in the callback 95% fail

    Sleeping does not release the callback group lock; the deadlock persists.