转自
单线程Spinning
ros::spin()是最简单的单线程自旋, 它会一直调用直到结束
用法: ros::spin();
另一个单线程spinning是ros::spinOnce(),它定期调用等待在那个点上的所有回调
用法: ros::spinOnce();
简单的我们自己实现一个用法相同的ros::spin()
这样: ros::getGlobalCallbackQueue()->callAvailable(ros::WallDuration(0.1));
ros::spinonce
这样: ros::getGlobalCallbackQueue()->callAvailable(ros::WallDuration(0));
以上,是它的基础用法,那么spin到底做了什么呢?
首先, 当我们调用ros::spin时, 会有一个互斥锁, 把你的回调队列加锁, 防止执行混乱.
然后, 检测如果回调队列不为空, 则读取回调队列
最后,当while(nh.ok())为true时, 调用当前队列中的所有函数,如果有不满足的, 会重新放回队列中
所以listener中, 就一直执行这ros::spin来监听话题了.从这样看来,spin和spinOnce的区别之一,就是while(nh::ok())执行块的大小了. 另一个是等待时间, spin在执行时, 会指定一个返回前可以等待调用的时间. spin会等待0.1s而spinonce不会
spinOnce使得pub/sub为非阻塞锁
spin是客户端的, 因此是阻塞的.
这样就很好理解talker要用SpinOnce,有需要talk的时候发出,没有的时候不发送.而listener一直在阻塞着听
这样,再来说之前很流传的一句关于解释spin的话, "所有的回调函数都是spin调用的". 这是一句形象而不准确的话. 回调函数一直等待在回调队列中, 只要条件一满足就会发生回调, 而spin的作用, 只是创建了线程给这个回调函数去执行它, 这样多线程就不会影响其他的作业.
之所以用spin, 是因为rospy不愿指定线程模型, 在程序中将线程暴露出来, 而用spin来把它封装起来. 但你可以用多线程调用任意数量的回调函数.
没有用户订阅, 服务和回调是不会被调用的.
多线程Spinning
多线程Spinning
roscpp内部支持调用多线程, 有两个:
ros::MultiThreadedSpinner
ros::MultiThreadedSpinner是阻塞微调, 类似于ros::spin(), 你可以在它的构造函数中指定线程数量, 但如果不指定或者设为0, 它会根据你的CPU内核数创建线程.
1 ros::MultiThreadedSpinner spinner(4); // Use 4 threads 2 spinner.spin(); // spin() will not return until the node has been shutdown
ros::AsyncSpinner (since 0.10)
一个更有用的线程spinner是AsyncSpinner. 与阻塞的spin()不同, 它有start()和stop()调用, 并且在销毁时自动停止
1 ros::AsyncSpinner spinner(4); // Use 4 threads 2 spinner.start(); 3 ros::waitForShutdown();
附官方说明:
Single-threaded Spinning
The simplest (and most common) version of single-threaded spinning is ros::spin():
切换行号显示
1 ros::init(argc, argv, "my_node");2 ros::NodeHandle nh;3 ros::Subscriber sub = nh.subscribe(...);4 ...5 ros::spin();
In this application all user callbacks will be called from within the ros::spin() call. ros::spin() will not return until the node has been shutdown, either through a call to ros::shutdown() or a Ctrl-C.
Another common pattern is to call ros::spinOnce() periodically:
切换行号显示
1 ros::Rate r(10); // 10 hz2 while (should_continue)3 {4 ... do some work, publish some messages, etc. ...5 ros::spinOnce();6 r.sleep();7 }
ros::spinOnce() will call all the callbacks waiting to be called at that point in time.
Implementing a spin() of our own is quite simple:
切换行号显示
1 #include <ros/callback_queue.h>2 ros::NodeHandle n;3 while (ros::ok())4 {5 ros::getGlobalCallbackQueue()->callAvailable(ros::WallDuration(0.1));6 }
and spinOnce() is simply:
切换行号显示
1 #include <ros/callback_queue.h>2 3 ros::getGlobalCallbackQueue()->callAvailable(ros::WallDuration(0));
Note: spin() and spinOnce() are really meant forsingle-threaded applications(单线程的), and are not optimized for being called from multiple threads at once. See the multi-threaded spinning section for information on spinning from multiple threads.
Multi-threaded Spinning
roscpp provides some built-in support for calling callbacks from multiple threads. There are two built-in options for this:
ros::MultiThreadedSpinner
-
MultiThreadedSpinner is ablocking spinner(阻塞的), similar to ros::spin(). You can specify a number of threads in its constructor, but if unspecified (or set to 0), it will use a thread for each CPU core.
切换行号显示1 ros::MultiThreadedSpinner spinner(4); // Use 4 threads2 spinner.spin(); // spin() will not return until the node has been shutdown3
ros::AsyncSpinner (since 0.10)
-
AsyncSpinner API (Jade)
-
A more useful threaded spinner is the AsyncSpinner(异步的). Instead of a blocking spin() call, it has start() and stop()calls, and will automatically stop when it is destroyed. An equivalent use of AsyncSpinner to the MultiThreadedSpinner example above, is:
切换行号显示1 ros::AsyncSpinner spinner(4); // Use 4 threads2 spinner.start();3 ros::waitForShutdown();