ros::Timer automatic clean up

asked 2018-10-18 22:01:24 -0500

KenYN gravatar image

updated 2018-10-18 23:28:47 -0500

I have a service, and in the service callback I have code like this:

bool service_callback(Request &request, Response &response)
{
    m_serviceTimer = nh.createTimer(ros::Duration(0.1),
                                    boost::bind(&service_timer, this,
                                                request.a, request.b),
                                    true);
    return true;
}

I start a timer to handle the service operations as otherwise I get deadlock if I try it in the service.

However, if I get two service_callback()s in quick succession, I end up destroying the first timer so it never gets processed. What's the best way to handle this situation? I thought an array of Timers then each time in the service remove all those with hasPending() == false, but there has to be a better and more generic way that can handle other fire-and-forget services like threads.


For the time being, I have "fixed" this by using a mutex, an atomic, and a BUSY return:

std::atomic<bool> m_pendingCreate{false};

bool service_callback(Request &request, Response &response)
{
    std::lock_guard<std::mutex> lg(m_mutex);
    if (m_pendingCreate)
    {
        response.status = SERVICE_BUSY;
    }
    else
    {
        m_pendingCreate = true;
        m_serviceTimer = nh.createTimer(ros::Duration(0.1),
                                        boost::bind(&service_timer, this,
                                                    request.a, request.b),
                                        true);
        response.status = SERVICE_OK;
    }
    return true;
}

void service_timer(....)
{
    // Whatever we need
    m_pendingCreate = false;
}

In the client, if the service returns SERVICE_BUSY we sleep for a few milliseconds and try again. However, as I wrote above, there must be some cleaner and generic way to do this!

edit retag flag offensive close merge delete

Comments

Services already provide blocking to prevent multiple clients from running at the same time. I would try to fix whatever causes the deadlock when you try to service the client in the service callback.

ahendrix gravatar image ahendrix  ( 2018-10-19 01:48:19 -0500 )edit

What's the best way to handle this situation?

What ^^ writes.

How are you spinning on your callback queues?

gvdhoorn gravatar image gvdhoorn  ( 2018-10-19 01:51:47 -0500 )edit

And pedantic, but this seems like a good example of an xy-problem.

gvdhoorn gravatar image gvdhoorn  ( 2018-10-19 01:52:33 -0500 )edit

I'm sending an ID for a bond::Bond, but I found if I created the bond in the callback things went wrong. I use just the usual node and nodelet queue spinning, so there's no spinning in the callback. On StackOverflow someone suggested std::thread::detach() but there's nothing for ros::Timer.

KenYN gravatar image KenYN  ( 2018-10-23 02:04:04 -0500 )edit