赞
踩
roscpp内部支持调用多线程, 有两个:
ros::MultiThreadedSpinner是阻塞微调, 类似于ros::spin(), 你可以在它的构造函数中指定线程数量, 但如果不指定或者设为0, 它会根据你的CPU内核数创建线程.
ros::MultiThreadedSpinner spinner(4); // Use 4 threads
spinner.spin(); // spin() will not return until the node has been shutdown
一个更有用的线程spinner是AsyncSpinner. 与阻塞的spin()不同, 它有start()和stop()调用, 并且在销毁时自动停止
ros::AsyncSpinner spinner(4); // Use 4 threads
spinner.start();
ros::waitForShutdown();
注意:
[FATAL] SingleThreadedSpinner: Attempt to spin a callback queue from two spinners, one of them being single-threaded. You might want to use a MultiThreadedSpinner instead.
这是因为有两个有两个spinners处理同一个callback queue,解决的方法就是设置不同的ros::CallbackQueue
callback queue ros wiki
ROS2 Client Interfaces (Client Libraries)
一个executor使用底层操作系统的一个或多个线程 to invoke the callbacks of subscriptions, timers, service servers, action servers, etc.
rclcpp::executors::SingleThreadedExecutor
SingleThreadedExecutor只允许串行处理。
rclcpp::executors::MultiThreadedExecutor
MultiThreadedExecutor创建可配置数量的线程以允许并行处理多个消息或事件
rclcpp::executors::StaticSingleThreadedExecutor
StaticSingleThreadedExecutor从订阅、定时器、服务、动作服务等方面优化扫描节点结构的runtime costs。它只在添加节点时执行一次扫描,而其他两类执行器则需要定期执行扫描以应对可能的变化。因此,StaticSingleThreadedExecutor只被用于 初始化时就已经创建了所有subscriptions,timers等 的节点。
上面三种执行器可以被用于多个nodes通过add_node()添加每个node
rclcpp::Node::SharedPtr node1 = ...
rclcpp::Node::SharedPtr node2 = ...
rclcpp::Node::SharedPtr node3 = ...
rclcpp::executors::StaticSingleThreadedExecutor executor;
executor.add_node(node1);
executor.add_node(node2);
executor.add_node(node2);
executor.spin();
不同执行器设置不同的优先级的案例:https://github.com/ros2/examples/tree/master/rclcpp/executors/cbg_executor
其中有关线程调度的知识请参考附录
ROS2中,回调是指一个函数,其调度和执行是由executor处理
callback_group回调组用于将回调函数打包分组,供executor调度执行。
ROS2提供了两种不同类型的回调组来控制回调的执行:
rclcpp::CallbackGroupType::MutuallyExclusiverclcpp::CallbackGroupType::Reentrant这些回调组以不同的方式限制其回调函数的执行
回调组的创建由node的create_callback_group成员函数执行
create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive)
如果用户在创建订阅、定时器等时没有指定任何回调组,则该实体将被分配到节点的默认回调组。默认回调组是互斥回调组,可以通过以下API查询
rclcpp: NodeBaseInterface::get_default_callback_group()
rclpy: Node.default_callback_group
rclcpp 中的 Executor 基类也有函数add_callback_group(..),它允许将回调组分配给不同的 Executor。通过使用操作系统调度程序配置底层线程,特定回调可以优先于其他回调。
有时候我们需要在线程执行代码里面对当前调用者线程进行操作,针对这种情况,C++11里面专门定义了一个命名空间this_thread,此命名空间也声明在<thread>头文件中,其中包括get_id()函数用来获取当前调用者线程的ID;yield()函数可以用来将调用者线程跳出运行状态,重新交给操作系统进行调度,即当前线程放弃执行,操作系统调度另一线程继续执行;sleep_until()函数是将线程休眠至某个指定的时刻(time point),该线程才被重新唤醒;sleep_for()函数是将线程休眠某个指定的时间片(time span),该线程才被重新唤醒,不过由于线程调度等原因,实际休眠实际可能比sleep_duration所表示的时间片更长。
int pthread_create(
pthread_t *restrict tidp,
const pthread_attr_t *restrict attr,
void *(*start_rtn)(void *),
void *restrict arg);
返回值:成功返回0;否则返回错误编号
注:restrict是c99标准引入的,它只可以用于限定和约束指针,并表明指针是访问一个数据对象的唯一且初始的方式.即它告诉编译器,所有修改该指针所指向内存中内容的操作都必须通过该指针来修改,而不能通过其它途径(其它变量或指针)来修改;这样做的好处是,能帮助编译器进行更好的优化代码,生成更有效率的汇编代码.
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr); // 默认 attr = NULL
int pthread_mutex_destory(pthread_mutex_t *mutex);// 返回值:成功返回0,否则返回错编号
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);// 返回值:成功返回0,否则返回错误编号
int pthread_mutex_trylock(pthread_mutex_t *mutex);// 非阻塞版本,如果mutex参数所指定的互斥锁已经被锁定的话,调用pthread_mutex_trylock函数不会阻塞当前线程,而是立即返回一个值来描述互斥锁的状况。
pthread_t pthread_self(void); // 返回调用线程的线程ID
线程属性结构如下:
typedef struct
{
int detachstate; //线程的分离状态
int schedpolicy; //线程调度策略
struct sched_param schedparam; //线程的调度参数
int inheritsched; //线程的继承性
int scope; //线程的作用域
size_t guardsize; //线程栈末尾的警戒缓冲区大小
int stackaddr_set;
void * stackaddr; //线程栈的位置
size_t stacksize; //线程栈的大小
}pthread_attr_t;
int pthread_attr_getschedpolicy(const pthread_attr_t *, int * policy);
int pthread_attr_setschedpolicy(pthread_attr_*, int policy);
参数:
返回:
若成功返回0,若失败返回-1。
int pthread_attr_getschedparam(const pthread_attr_t * attr,struct
sched_param * param);
int pthread_attr_setschedparam(pthread_attr_t * attr,const struct
sched_param * param);
参数:
attr :线程变量属性
param :sched_parm 结构体
struct sched_param
{
int sched_priority; //参数的本质就是优先级,大的权值对应高的优先级!
};
系统支持的最大和最小的优先级值可以用函数:
int sched_get_priority_max( int policy );
int sched_get_priority_min( int policy );
返回:
若成功返回0,若失败返回-1。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。