ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
1

roscpp Callback Thread Safety SEGFAULT

asked 2016-02-19 23:56:55 -0500

solb22 gravatar image

updated 2016-02-20 01:59:00 -0500

I'm currently subscribing to every topic ever published in my program via ShapeShifter, and deserializing as necessary. This works great, but I'm receiving SEGFAULTs when using ros::AsyncSpinner. I'm essentially trying to create a live rqt_graph, which monitors latency between sent and received messages.

Why is the below not threadsafe? From my console, it looks like the shared::ptr to Shapeshifter msg within my callback get changed on me without me finishing the callback. Is it not safe to pass shared::ptr to ROS callback threads?

ERROR MESSAGE

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffea7fc700 (LWP 31281)]
__memcpy_sse2_unaligned () at ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S:79
79  ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S: No such file or directory.

MAIN

int main(int argc, char* argv[])
{
  ros::init(argc, argv, "performance_tracker_node");

  ros::AsyncSpinner spinner(4);
  spinner.start();

  // Loop on the main thread and search for new topics being published
  // If the topic caught doesn't exist in our Node list yet, add it
  while(ros::ok()){
       //Code that finds new topics not included
                PerformanceTracker newNode = PerformanceTracker(info.name);
                performanceNodes.insert(std::pair<std::string, PerformanceTracker>(info.name, newNode));
     }
      ros::waitForShutdown;
}

Performance Tracker Constructor

PerformanceTracker::PerformanceTracker(std::string topicName):
_topicName(topicName)
 {
   ros::NodeHandle nh("~");
  _nh = nh;
  // Subscribe To Generic Message 
 _sub =  _nh.subscribe( _topicName, 10, &PerformanceTracker::topicCallback, this);
}

Performance Tracker Callback

void PerformanceTracker::topicCallback(const boost::shared_ptr<topic_tools::ShapeShifter> msg){
//Current Time
ros::Time begin = ros::Time::now();

    //Prevent OOB error by only checking msgs that are at least the size of a header msg 
    if(msg->size() >= sizeof(std_msgs::Header)){
        //Deserialize message
        std_msgs::Header header;
        uint8_t buf[msg->size()];
        ros::serialization::OStream stream(buf, msg->size());
        msg->write(stream);
        header.seq = ((uint32_t *)buf)[0];
        header.stamp.sec = ((int32_t *)buf)[1];
        header.stamp.nsec = ((int32_t *)buf)[2];

        // Delays greater than 1 hour are clearly wrong., and the header doesn't exist, so skip this
        double lagTime = (begin-header.stamp).toSec();
        if(lagTime > 3600){
            // Skip this topic in the future
            std::cout << "Topic " << _topicName <<  " sent at " <<  header.stamp << " returned nonsense time for " << lagTime <<  " seconds" << std::endl;
            _nh.shutdown();
        }
       //if delayed, then log time lag
        else if(lagTime > 1){
            std::cout << "Topic " << _topicName <<  " sent at " <<  header.stamp << " delayed for" << lagTime <<  " seconds" << std::endl;
        }
    }
     // Remove topic for future if topic message type is too small 
    else{
        // Skip this topic in the future
        std::cout << "Topic " << _topicName <<  " message size was smaller than just a std::msg Header, and likely did not have a header "<< std::endl;
        _nh.shutdown();
    }
 }
edit retag flag offensive close merge delete

1 Answer

Sort by ยป oldest newest most voted
1

answered 2016-02-20 13:12:50 -0500

ahendrix gravatar image

boost::shared_ptr are explicitly designed to be shared between threads; the function prototype for your callback seems fine.

I would run your program through a debugger (gdb) to determine the location of the segfault.

(It's also odd that you're calling _nh.shutdown() when you want to unsubscribe from a single topic, because this will shut down your entire process; not just a single subscriber).

edit flag offensive delete link more

Comments

I posted the error from gdb, Ill post the full stacktrace. I'm create a new nodehandle for each topic, and then calling shutdown(). Is that not allowed? I wasn't aware of how to use only one nodehandle for the entire node and unsubscribe from a particular topic

solb22 gravatar image solb22  ( 2016-02-20 18:01:45 -0500 )edit

roscpp only creates one node per process, regardless of how many NodeHandles you create. Calling shutdown on any NodeHandle shuts down the entire process. If you want to stop a particular subscriber, call the unsubscribe method on that subscriber.

ahendrix gravatar image ahendrix  ( 2016-02-20 23:24:24 -0500 )edit

I don't see an unsubscribe member function on ros::Subscriber. I only see shutdown

solb22 gravatar image solb22  ( 2016-02-21 05:02:04 -0500 )edit

Sorry; that's what I meant.

ahendrix gravatar image ahendrix  ( 2016-02-21 14:25:57 -0500 )edit

Did you ever figure this out? I think i'm having the same problem.

jlack gravatar image jlack  ( 2017-11-14 07:32:17 -0500 )edit

Question Tools

2 followers

Stats

Asked: 2016-02-19 23:56:55 -0500

Seen: 1,107 times

Last updated: Nov 14 '17