目录
一、简要介绍
这段代码展示了 ROS 2 中rclcpp_action
命名空间下ServerGoalHandleBase
类的成员函数实现。ServerGoalHandleBase
在动作服务器中扮演着关键的角色,负责与目标交互并管理其状态。
1. 文件核心功能
析构函数
ServerGoalHandleBase::~ServerGoalHandleBase()
:空的析构函数,在对象销毁时可能执行一些清理操作,但目前没有具体实现。
状态判断方法
is_canceling()
:通过锁定互斥锁,获取目标的状态,并判断是否处于取消中状态。如果获取状态过程中出现错误,会抛出相应的异常。is_active()
:锁定互斥锁后,直接调用底层函数判断目标是否处于活跃状态。is_executing()
:与is_canceling()
类似,获取目标状态并判断是否处于执行中状态。
状态改变方法
_abort()
、_succeed()
、_cancel_goal()
、_canceled()
、_execute()
:这些方法分别用于改变目标的状态为中止、成功、请求取消、已取消和开始执行。每个方法都通过锁定互斥锁,调用底层的rcl_action
函数来更新目标状态。如果更新过程中出现错误,会抛出异常。
尝试取消方法
try_canceling()
:这个方法首先检查目标是否可取消,如果可取消则尝试将目标状态转换为取消中,然后再次获取状态判断是否成功取消。如果任何步骤出现错误,返回false
。
2. 使用场景
在 ROS 2 的动作服务器中,ServerGoalHandleBase
的这些成员函数被用于管理和操作目标的状态。例如,当需要判断目标是否正在被取消、是否活跃或是否执行中时,可以调用相应的状态判断方法。当需要改变目标的状态,如中止目标、标记目标成功或取消目标时,可以调用对应的状态改变方法。而try_canceling()
方法则在需要尝试取消目标时使用,例如在对象销毁前如果目标未达到终端状态,可以尝试取消目标以避免资源泄漏。
3. 总结
这段代码实现了ServerGoalHandleBase
类的关键成员函数,为 ROS 2 动作服务器提供了强大的目标状态管理功能。通过这些函数,动作服务器可以准确地判断目标的状态,并在需要时改变目标的状态,确保动作服务器的稳定运行和正确响应。
二、源码与解析
// Copyright 2018 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <memory>
#include "rcl_action/action_server.h"
#include "rcl_action/goal_handle.h"
#include "rclcpp_action/server_goal_handle.hpp"
#include "rclcpp/exceptions.hpp"
namespace rclcpp_action
{
ServerGoalHandleBase::~ServerGoalHandleBase()
{
}
bool
ServerGoalHandleBase::is_canceling() const
{
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
rcl_action_goal_state_t state = GOAL_STATE_UNKNOWN;
rcl_ret_t ret = rcl_action_goal_handle_get_status(rcl_handle_.get(), &state);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret, "Failed to get goal handle state");
}
return GOAL_STATE_CANCELING == state;
}
bool
ServerGoalHandleBase::is_active() const
{
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
return rcl_action_goal_handle_is_active(rcl_handle_.get());
}
bool
ServerGoalHandleBase::is_executing() const
{
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
rcl_action_goal_state_t state = GOAL_STATE_UNKNOWN;
rcl_ret_t ret = rcl_action_goal_handle_get_status(rcl_handle_.get(), &state);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret, "Failed to get goal handle state");
}
return GOAL_STATE_EXECUTING == state;
}
void
ServerGoalHandleBase::_abort()
{
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
rcl_ret_t ret = rcl_action_update_goal_state(rcl_handle_.get(), GOAL_EVENT_ABORT);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
}
void
ServerGoalHandleBase::_succeed()
{
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
rcl_ret_t ret = rcl_action_update_goal_state(rcl_handle_.get(), GOAL_EVENT_SUCCEED);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
}
void
ServerGoalHandleBase::_cancel_goal()
{
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
rcl_ret_t ret = rcl_action_update_goal_state(rcl_handle_.get(), GOAL_EVENT_CANCEL_GOAL);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
}
void
ServerGoalHandleBase::_canceled()
{
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
rcl_ret_t ret = rcl_action_update_goal_state(rcl_handle_.get(), GOAL_EVENT_CANCELED);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
}
void
ServerGoalHandleBase::_execute()
{
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
rcl_ret_t ret = rcl_action_update_goal_state(rcl_handle_.get(), GOAL_EVENT_EXECUTE);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
}
bool
ServerGoalHandleBase::try_canceling() noexcept
{
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
rcl_ret_t ret;
// Check if the goal is cancelable
const bool is_cancelable = rcl_action_goal_handle_is_cancelable(rcl_handle_.get());
if (is_cancelable) {
// Transition to CANCELING
ret = rcl_action_update_goal_state(rcl_handle_.get(), GOAL_EVENT_CANCEL_GOAL);
if (RCL_RET_OK != ret) {
return false;
}
}
rcl_action_goal_state_t state = GOAL_STATE_UNKNOWN;
// Get the current state
ret = rcl_action_goal_handle_get_status(rcl_handle_.get(), &state);
if (RCL_RET_OK != ret) {
return false;
}
// If it's canceling, cancel it
if (GOAL_STATE_CANCELING == state) {
ret = rcl_action_update_goal_state(rcl_handle_.get(), GOAL_EVENT_CANCELED);
return RCL_RET_OK == ret;
}
return false;
}
} // namespace rclcpp_action
以下是对各个成员函数的进一步解析:
一、析构函数
ServerGoalHandleBase::~ServerGoalHandleBase()
{
}
这个析构函数目前为空,可能在未来的版本中会添加一些资源清理的操作。
二、状态判断方法
1. is_canceling()
bool
ServerGoalHandleBase::is_canceling() const
{
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
rcl_action_goal_state_t state = GOAL_STATE_UNKNOWN;
rcl_ret_t ret = rcl_action_goal_handle_get_status(rcl_handle_.get(), &state);
if (RCL_RET_OK!= ret) {
rclcpp::exceptions::throw_from_rcl_error(ret, "Failed to get goal handle state");
}
return GOAL_STATE_CANCELING == state;
}
这段代码是 ServerGoalHandleBase
类中的一个成员函数 is_canceling()
的实现。这个函数用于检查一个目标(goal)是否被请求取消。下面是对这段代码的详细解析:
函数签名
bool ServerGoalHandleBase::is_canceling() const
- 返回类型:
bool
- 如果目标处于取消状态则返回true
,否则返回false
。 - 函数名:
is_canceling
- 检查目标是否被请求取消。 - 常量成员函数:
(const)
- 表示这个函数不会修改类的任何成员变量,只读取它们。
函数体
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
rcl_action_goal_state_t state = GOAL_STATE_UNKNOWN;
rcl_ret_t ret = rcl_action_goal_handle_get_status(rcl_handle_.get(), &state);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret, "Failed to get goal handle state");
}
return GOAL_STATE_CANCELING == state;
-
Mutex Locking:
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
- 这行代码使用了
std::lock_guard
来自动锁定互斥锁rcl_handle_mutex_
。std::lock_guard
是一个 RAII(Resource Acquisition Is Initialization)风格的对象,它在构造时锁定互斥锁,在析构时自动解锁互斥锁。这样可以确保即使发生异常,互斥锁也会被正确解锁。
- 这行代码使用了
-
获取目标状态:
rcl_action_goal_state_t state = GOAL_STATE_UNKNOWN;
- 初始化状态变量
state
为GOAL_STATE_UNKNOWN
。这通常是为了避免使用未初始化的数据。
- 初始化状态变量
rcl_ret_t ret = rcl_action_goal_handle_get_status(rcl_handle_.get(), &state);
- 调用
rcl_action_goal_handle_get_status
函数来获取目标的状态,并将结果存储在state
变量中。这里使用了智能指针rcl_handle_
的.get()
方法来获取底层的rcl_action_goal_handle_t
对象指针。
- 调用
-
错误处理:
if (RCL_RET_OK != ret) { ... }
- 检查
rcl_action_goal_handle_get_status
的返回值ret
是否等于RCL_RET_OK
。如果不等于RCL_RET_OK
,则表示获取状态失败。
- 检查
rclcpp::exceptions::throw_from_rcl_error(ret, "Failed to get goal handle state");
- 如果获取状态失败,这里会抛出一个异常。
rclcpp::exceptions::throw_from_rcl_error
函数会根据ret
的值抛出相应的异常,并附带错误信息。
- 如果获取状态失败,这里会抛出一个异常。
-
返回值:
return GOAL_STATE_CANCELING == state;
- 如果
state
等于GOAL_STATE_CANCELING
,则返回true
;否则返回false
。这表示如果目标正处于取消状态,则返回true
。
- 如果
成员变量
private:
std::shared_ptr<rcl_action_goal_handle_t> rcl_handle_;
mutable std::mutex rcl_handle_mutex_;
-
std::shared_ptr<rcl_action_goal_handle_t> rcl_handle_;
- 一个智能指针,持有
rcl_action_goal_handle_t
类型的对象。这个对象是由 ROS 2 的底层库(rcl_action)管理的目标句柄,用于与目标进行交互。
- 一个智能指针,持有
-
mutable std::mutex rcl_handle_mutex_;
- 一个互斥锁,用于保护对
rcl_action_goal_handle_t
对象的访问。由于rcl_action_goal_handle_t
可能会被多个线程访问,因此需要使用互斥锁来保证数据的一致性和安全性。
- 一个互斥锁,用于保护对
-
Mutex Locking:
- 通过使用
std::lock_guard
,函数在进入时自动锁定互斥锁rcl_handle_mutex_
,并在函数退出时自动解锁。这确保了在多线程环境下对rcl_action_goal_handle_t
对象的访问是线程安全的。
- 通过使用
-
获取目标状态:
- 通过调用
rcl_action_goal_handle_get_status
函数来获取目标的状态。这个函数接受一个指向rcl_action_goal_handle_t
的指针以及一个指向rcl_action_goal_state_t
的指针来接收状态值。
- 通过调用
-
错误处理:
- 如果
rcl_action_goal_handle_get_status
函数返回非RCL_RET_OK
的值,说明获取状态失败,此时会抛出一个异常。
- 如果
-
返回值:
- 根据获取到的状态值
state
,判断是否等于GOAL_STATE_CANCELING
。如果是,则返回true
表示目标已被请求取消;否则返回false
。
- 根据获取到的状态值
通过这种方式,is_canceling()
函数提供了一个安全、可靠的方法来检查目标是否被请求取消,同时确保了对底层 rcl_action_goal_handle_t
对象的线程安全访问。
附加解析1:
template<typename _Mutex>
class lock_guard
{
public:
typedef _Mutex mutex_type;
explicit lock_guard(mutex_type& __m) : _M_device(__m)
{ _M_device.lock(); }
lock_guard(mutex_type& __m, adopt_lock_t) noexcept : _M_device(__m)
{ } // calling thread owns mutex
~lock_guard()
{ _M_device.unlock(); }
lock_guard(const lock_guard&) = delete;
lock_guard& operator=(const lock_guard&) = delete;
private:
mutex_type& _M_device;
};
这段代码展示了C++标准库中的 std::lock_guard
类模板的一个简化版本。std::lock_guard
是一个用于管理互斥锁(mutex)的类模板,它实现了RAII(Resource Acquisition Is Initialization)模式,即资源的获取是在构造函数中进行的,而资源的释放是在析构函数中进行的。这有助于确保即使在异常情况下,锁也能被正确地释放,从而避免死锁。
类模板定义
template<typename _Mutex>
class lock_guard
{
public:
typedef _Mutex mutex_type;
template<typename _Mutex>
:lock_guard
是一个模板类,它接受一个类型参数_Mutex
,该类型通常是一个互斥锁类型,如std::mutex
。typedef _Mutex mutex_type;
: 定义了一个类型别名mutex_type
,它是指向模板参数_Mutex
的类型别名。
构造函数
explicit lock_guard(mutex_type& __m) : _M_device(__m)
{ _M_device.lock(); }
explicit lock_guard(mutex_type& __m) : _M_device(__m)
: 这是一个构造函数,它接受一个mutex_type
的引用作为参数。explicit
关键字防止了隐式转换。构造函数初始化lock_guard
类的_M_device
成员变量,该成员变量是一个互斥锁的引用。{ _M_device.lock(); }
: 构造函数体内的代码块中,调用了_M_device
的lock()
方法来获取互斥锁。
构造函数(采用锁)
lock_guard(mutex_type& __m, adopt_lock_t) noexcept : _M_device(__m)
{ } // calling thread owns mutex
lock_guard(mutex_type& __m, adopt_lock_t) noexcept : _M_device(__m)
: 这个构造函数接受一个mutex_type
的引用和一个adopt_lock_t
标记作为参数。adopt_lock_t
是一个类型标签,用来表示当前线程已经拥有互斥锁的所有权,因此不需要在构造函数中再次获取锁。noexcept
: 表示构造函数不会抛出异常。{ }
: 构造函数体为空,因为互斥锁已经在其他地方被锁定,所以不需要在这里再次锁定。
析构函数
~lock_guard()
{ _M_device.unlock(); }
~lock_guard()
: 析构函数负责释放互斥锁。当lock_guard
实例超出作用域时,析构函数将被调用,从而调用_M_device
的unlock()
方法来释放互斥锁。
私有成员变量
private:
mutex_type& _M_device;
mutex_type& _M_device;
: 这是一个私有成员变量,它是一个对mutex_type
的引用。这个引用保持了对互斥锁的访问。
移除拷贝构造函数和赋值运算符
lock_guard(const lock_guard&) = delete;
lock_guard& operator=(const lock_guard&) = delete;
lock_guard(const lock_guard&) = delete;
: 删除拷贝构造函数,意味着不能创建lock_guard
的拷贝。这是因为拷贝构造函数会导致互斥锁的所有权变得模糊不清,可能导致程序错误。lock_guard& operator=(const lock_guard&) = delete;
: 删除赋值运算符,意味着不能将一个lock_guard
对象赋值给另一个。同样,这也为了避免所有权问题。
附加解析2:
explicit lock_guard(mutex_type& __m) : _M_device(__m)
{ _M_device.lock(); }
std::shared_ptr<rcl_action_goal_handle_t> rcl_handle_;
mutable std::mutex rcl_handle_mutex_;
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
这段代码涉及到了 std::lock_guard
和 std::mutex
的使用。下面是针对这段代码的详细解析:
std::lock_guard
类模板的构造函数
explicit lock_guard(mutex_type& __m) : _M_device(__m)
{ _M_device.lock(); }
-
explicit
关键字:explicit
关键字用于构造函数或转换运算符,它禁止隐式类型转换。这意味着你不能使用lock_guard
的构造函数来进行隐式的类型转换。例如,你不能将一个std::mutex
直接传递给一个期望lock_guard
的函数,必须显式地创建lock_guard
实例。
-
构造函数:
lock_guard
的构造函数接受一个mutex_type
类型的引用__m
。这里的mutex_type
是std::lock_guard
模板的一个类型参数,通常会被指定为std::mutex
或者其他互斥锁类型。lock_guard
的构造函数初始化了一个名为_M_device
的成员变量,该成员变量是一个对__m
的引用。- 构造函数体内调用
_M_device.lock()
来锁定互斥锁。这是通过std::lock_guard
的 RAII(Resource Acquisition Is Initialization)机制来完成的,确保互斥锁在lock_guard
实例创建时被锁定。
std::mutex
和 std::lock_guard
的使用
mutable std::mutex rcl_handle_mutex_;
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
-
std::mutex
:rcl_handle_mutex_
是一个std::mutex
类型的私有成员变量。它用于保护对rcl_action_goal_handle_t
对象的访问,确保在多线程环境下对这个对象的访问是线程安全的。mutable
关键字允许在const
成员函数中修改这个成员变量。这是因为std::lock_guard
需要锁定和解锁互斥锁,这通常涉及到修改互斥锁的状态。在const
成员函数中使用mutable
允许我们在不改变对象状态的情况下锁定和解锁互斥锁。
-
std::lock_guard
的实例化:std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
创建了一个std::lock_guard
实例,名为lock
,它接受rcl_handle_mutex_
作为参数。- 当
lock
实例被创建时,rcl_handle_mutex_
会被锁定。这确保了在lock
实例的作用域内,rcl_handle_mutex_
是被锁定的,不允许其他线程同时访问。 - 当
lock
实例超出作用域时,它的析构函数会被自动调用,从而解锁rcl_handle_mutex_
。
综合解析
在 ServerGoalHandleBase::is_canceling()
函数中,std::lock_guard
的使用如下:
-
保护代码块:
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
保护了整个函数体内的代码块。这意味着在函数体执行期间,rcl_handle_mutex_
是被锁定的,确保了对rcl_action_goal_handle_t
对象的线程安全访问。- 即使函数体中抛出了异常,
std::lock_guard
的析构函数也会确保rcl_handle_mutex_
被解锁。
-
线程安全:
- 通过使用
std::lock_guard
,我们无需显式地调用lock()
和unlock()
方法来管理互斥锁。这有助于避免死锁和其他并发问题。 std::lock_guard
的使用还简化了代码,使得锁的管理更加自动化和可靠。
- 通过使用
总结来说,std::lock_guard
和 std::mutex
的组合使用提供了线程安全的互斥锁管理机制,简化了多线程编程,并提高了代码的安全性和可维护性。
2. is_active()
bool
ServerGoalHandleBase::is_active() const
{
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
return rcl_action_goal_handle_is_active(rcl_handle_.get());
}
这段代码是 ServerGoalHandleBase
类中的一个成员函数 is_active()
的实现。这个函数用于检查一个目标(goal)是否处于活动状态。下面是对这段代码的详细解析:
函数签名
bool ServerGoalHandleBase::is_active() const
- 返回类型:
bool
- 如果目标处于活动状态则返回true
,否则返回false
。 - 函数名:
is_active
- 检查目标是否处于活动状态。 - 常量成员函数:
(const)
- 表示这个函数不会修改类的任何成员变量,只读取它们。
函数体
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
return rcl_action_goal_handle_is_active(rcl_handle_.get());
-
Mutex Locking:
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
- 这行代码使用了
std::lock_guard
来自动锁定互斥锁rcl_handle_mutex_
。std::lock_guard
是一个 RAII(Resource Acquisition Is Initialization)风格的对象,它在构造时锁定互斥锁,在析构时自动解锁互斥锁。这样可以确保即使发生异常,互斥锁也会被正确解锁。
- 这行代码使用了
-
检查目标状态:
return rcl_action_goal_handle_is_active(rcl_handle_.get());
- 调用
rcl_action_goal_handle_is_active
函数来检查目标是否处于活动状态。这里使用了智能指针rcl_handle_
的.get()
方法来获取底层的rcl_action_goal_handle_t
对象指针。 - 这个函数返回一个布尔值,指示目标是否处于活动状态。
- 调用
成员变量
private:
std::shared_ptr<rcl_action_goal_handle_t> rcl_handle_;
mutable std::mutex rcl_handle_mutex_;
-
std::shared_ptr<rcl_action_goal_handle_t> rcl_handle_;
- 一个智能指针,持有
rcl_action_goal_handle_t
类型的对象。这个对象是由 ROS 2 的底层库(rcl_action)管理的目标句柄,用于与目标进行交互。
- 一个智能指针,持有
-
mutable std::mutex rcl_handle_mutex_;
- 一个互斥锁,用于保护对
rcl_action_goal_handle_t
对象的访问。由于rcl_action_goal_handle_t
可能会被多个线程访问,因此需要使用互斥锁来保证数据的一致性和安全性。
- 一个互斥锁,用于保护对
总结
这段代码的主要功能是安全地检查目标是否处于活动状态。通过使用 std::lock_guard
和 std::mutex
来确保线程安全,具体解析如下:
-
Mutex Locking:
- 通过使用
std::lock_guard
,函数在进入时自动锁定互斥锁rcl_handle_mutex_
,并在函数退出时自动解锁。这确保了在多线程环境下对rcl_action_goal_handle_t
对象的访问是线程安全的。
- 通过使用
-
检查目标状态:
- 通过调用
rcl_action_goal_handle_is_active
函数来检查目标是否处于活动状态。这个函数接受一个指向rcl_action_goal_handle_t
的指针,并返回一个布尔值来指示目标的状态。
- 通过调用
-
返回值:
- 根据
rcl_action_goal_handle_is_active
函数的返回值直接返回true
或false
。如果目标处于活动状态,则返回true
;否则返回false
。
- 根据
通过这种方式,is_active()
函数提供了一个安全、可靠的方法来检查目标是否处于活动状态,同时确保了对底层 rcl_action_goal_handle_t
对象的线程安全访问。
3. is_executing()
bool
ServerGoalHandleBase::is_executing() const
{
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
rcl_action_goal_state_t state = GOAL_STATE_UNKNOWN;
rcl_ret_t ret = rcl_action_goal_handle_get_status(rcl_handle_.get(), &state);
if (RCL_RET_OK!= ret) {
rclcpp::exceptions::throw_from_rcl_error(ret, "Failed to get goal handle state");
}
return GOAL_STATE_EXECUTING == state;
}
与is_canceling()
类似,获取目标状态并判断是否处于执行中状态。
三、状态改变方法
1. _abort()
void
ServerGoalHandleBase::_abort()
{
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
rcl_ret_t ret = rcl_action_update_goal_state(rcl_handle_.get(), GOAL_EVENT_ABORT);
if (RCL_RET_OK!= ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
}
这段代码是 ServerGoalHandleBase
类中的一个成员函数 _abort()
的实现。这个函数用于向目标(goal)发送一个终止(abort)事件。下面是对这段代码的详细解析:
函数签名
void ServerGoalHandleBase::_abort()
- 返回类型:
void
- 这个函数没有返回值。 - 函数名:
_abort
- 发送一个终止事件给目标。 - 无参数 - 这个函数不接受任何参数。
函数体
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
rcl_ret_t ret = rcl_action_update_goal_state(rcl_handle_.get(), GOAL_EVENT_ABORT);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
-
Mutex Locking:
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
- 这行代码使用了
std::lock_guard
来自动锁定互斥锁rcl_handle_mutex_
。std::lock_guard
是一个 RAII(Resource Acquisition Is Initialization)风格的对象,它在构造时锁定互斥锁,在析构时自动解锁互斥锁。这样可以确保即使发生异常,互斥锁也会被正确解锁。
- 这行代码使用了
-
更新目标状态:
rcl_ret_t ret = rcl_action_update_goal_state(rcl_handle_.get(), GOAL_EVENT_ABORT);
- 调用
rcl_action_update_goal_state
函数来向目标发送一个终止事件。这里使用了智能指针rcl_handle_
的.get()
方法来获取底层的rcl_action_goal_handle_t
对象指针。 - 函数接受两个参数:目标句柄的指针和一个事件类型,这里是
GOAL_EVENT_ABORT
,表示终止事件。 - 函数返回一个
rcl_ret_t
类型的值,表示操作的结果。
- 调用
-
错误处理:
if (RCL_RET_OK != ret) { ... }
- 检查
rcl_action_update_goal_state
的返回值ret
是否等于RCL_RET_OK
。如果不等于RCL_RET_OK
,则表示操作失败。
- 检查
rclcpp::exceptions::throw_from_rcl_error(ret);
- 如果操作失败,这里会抛出一个异常。
rclcpp::exceptions::throw_from_rcl_error
函数会根据ret
的值抛出相应的异常。
- 如果操作失败,这里会抛出一个异常。
2. _succeed()
void
ServerGoalHandleBase::_succeed()
{
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
rcl_ret_t ret = rcl_action_update_goal_state(rcl_handle_.get(), GOAL_EVENT_SUCCEED);
if (RCL_RET_OK!= ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
}
将目标状态更新为成功状态。
3. _cancel_goal()
void
ServerGoalHandleBase::_cancel_goal()
{
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
rcl_ret_t ret = rcl_action_update_goal_state(rcl_handle_.get(), GOAL_EVENT_CANCEL_GOAL);
if (RCL_RET_OK!= ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
}
请求取消目标。
4. _canceled()
void
ServerGoalHandleBase::_canceled()
{
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
rcl_ret_t ret = rcl_action_update_goal_state(rcl_handle_.get(), GOAL_EVENT_CANCELED);
if (RCL_RET_OK!= ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
}
将目标状态更新为已取消状态。
5. _execute()
void
ServerGoalHandleBase::_execute()
{
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
rcl_ret_t ret = rcl_action_update_goal_state(rcl_handle_.get(), GOAL_EVENT_EXECUTE);
if (RCL_RET_OK!= ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
}
启动目标的执行。
四、尝试取消方法
bool
ServerGoalHandleBase::try_canceling() noexcept
{
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
rcl_ret_t ret;
// Check if the goal is cancelable
const bool is_cancelable = rcl_action_goal_handle_is_cancelable(rcl_handle_.get());
if (is_cancelable) {
// Transition to CANCELING
ret = rcl_action_update_goal_state(rcl_handle_.get(), GOAL_EVENT_CANCEL_GOAL);
if (RCL_RET_OK!= ret) {
return false;
}
}
rcl_action_goal_state_t state = GOAL_STATE_UNKNOWN;
// Get the current state
ret = rcl_action_goal_handle_get_status(rcl_handle_.get(), &state);
if (RCL_RET_OK!= ret) {
return false;
}
// If it's canceling, cancel it
if (GOAL_STATE_CANCELING == state) {
ret = rcl_action_update_goal_state(rcl_handle_.get(), GOAL_EVENT_CANCELED);
return RCL_RET_OK == ret;
}
return false;
}
这段代码是 ServerGoalHandleBase
类中的一个成员函数 try_canceling()
的实现。这个函数尝试取消一个目标(goal),如果目标是可以取消的,则将其状态设置为取消中(canceling),并且如果目标已经是取消中状态,则尝试将其设置为已取消(canceled)。下面是对这段代码的详细解析:
函数签名
bool ServerGoalHandleBase::try_canceling() noexcept
- 返回类型:
bool
- 如果成功尝试取消目标,则返回true
;否则返回false
。 - 函数名:
try_canceling
- 尝试取消目标。 - 无参数 - 这个函数不接受任何参数。
noexcept
- 表明这个函数不会抛出异常。
函数体
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
rcl_ret_t ret;
// Check if the goal is cancelable
const bool is_cancelable = rcl_action_goal_handle_is_cancelable(rcl_handle_.get());
if (is_cancelable) {
// Transition to CANCELING
ret = rcl_action_update_goal_state(rcl_handle_.get(), GOAL_EVENT_CANCEL_GOAL);
if (RCL_RET_OK != ret) {
return false;
}
}
rcl_action_goal_state_t state = GOAL_STATE_UNKNOWN;
// Get the current state
ret = rcl_action_goal_handle_get_status(rcl_handle_.get(), &state);
if (RCL_RET_OK != ret) {
return false;
}
// If it's canceling, cancel it
if (GOAL_STATE_CANCELING == state) {
ret = rcl_action_update_goal_state(rcl_handle_.get(), GOAL_EVENT_CANCELED);
return RCL_RET_OK == ret;
}
return false;
-
Mutex Locking:
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
- 这行代码使用了
std::lock_guard
来自动锁定互斥锁rcl_handle_mutex_
。std::lock_guard
是一个 RAII(Resource Acquisition Is Initialization)风格的对象,它在构造时锁定互斥锁,在析构时自动解锁互斥锁。这样可以确保即使发生异常,互斥锁也会被正确解锁。
- 这行代码使用了
-
检查目标是否可取消:
const bool is_cancelable = rcl_action_goal_handle_is_cancelable(rcl_handle_.get());
- 调用
rcl_action_goal_handle_is_cancelable
函数来检查目标是否处于可取消状态。这里使用了智能指针rcl_handle_
的.get()
方法来获取底层的rcl_action_goal_handle_t
对象指针。 - 函数返回一个布尔值,指示目标是否可取消。
- 调用
-
尝试设置为取消中状态:
- 如果目标是可取消的,则尝试将其状态设置为取消中。
ret = rcl_action_update_goal_state(rcl_handle_.get(), GOAL_EVENT_CANCEL_GOAL);
- 调用
rcl_action_update_goal_state
函数来向目标发送一个取消事件。这里使用了智能指针rcl_handle_
的.get()
方法来获取底层的rcl_action_goal_handle_t
对象指针。 - 函数接受两个参数:目标句柄的指针和一个事件类型
GOAL_EVENT_CANCEL_GOAL
。 - 函数返回一个
rcl_ret_t
类型的值,表示操作的结果。
- 调用
- 如果设置失败,则返回
false
。
-
获取当前状态:
rcl_action_goal_state_t state = GOAL_STATE_UNKNOWN;
- 初始化状态变量
state
为GOAL_STATE_UNKNOWN
。
- 初始化状态变量
ret = rcl_action_goal_handle_get_status(rcl_handle_.get(), &state);
- 调用
rcl_action_goal_handle_get_status
函数来获取目标的状态,并将结果存储在state
变量中。这里使用了智能指针rcl_handle_
的.get()
方法来获取底层的rcl_action_goal_handle_t
对象指针。 - 函数返回一个
rcl_ret_t
类型的值,表示操作的结果。
- 调用
- 如果获取状态失败,则返回
false
。
-
尝试设置为已取消状态:
- 如果目标当前状态为取消中,则尝试将其设置为已取消。
ret = rcl_action_update_goal_state(rcl_handle_.get(), GOAL_EVENT_CANCELED);
- 调用
rcl_action_update_goal_state
函数来向目标发送一个已取消事件。这里使用了智能指针rcl_handle_
的.get()
方法来获取底层的rcl_action_goal_handle_t
对象指针。 - 函数接受两个参数:目标句柄的指针和一个事件类型
GOAL_EVENT_CANCELED
。 - 函数返回一个
rcl_ret_t
类型的值,表示操作的结果。
- 调用
- 如果设置成功,则返回
true
;否则返回false
。
-
返回值:
- 如果目标不是可取消状态,或者在尝试设置状态时遇到错误,则返回
false
。
- 如果目标不是可取消状态,或者在尝试设置状态时遇到错误,则返回