Boost mutex error when using SimpleActionClient with std::unique_ptr
The minimal example that reproduces the issue (modified from this example) is as follows
#include <memory>
#include <gtest/gtest.h>
#include <actionlib/TestAction.h>
#include <actionlib/client/simple_action_client.h>
using namespace actionlib;
std::unique_ptr<SimpleActionClient<TestAction>> client;
TEST(SimpleClient, easy_wait_test)
{
bool started = client->waitForServer(ros::Duration(10.0));
ASSERT_TRUE(started);
TestGoal goal;
SimpleClientGoalState state(SimpleClientGoalState::LOST);
goal.goal = 1;
state = client->sendGoalAndWait(goal, ros::Duration(10,0), ros::Duration(10,0));
EXPECT_TRUE( state == SimpleClientGoalState::SUCCEEDED)
<< "Expected [SUCCEEDED], but goal state is [" << client->getState().toString() << "]";
goal.goal = 4;
state = client->sendGoalAndWait(goal, ros::Duration(2,0), ros::Duration(1,0));
EXPECT_TRUE( state == SimpleClientGoalState::PREEMPTED)
<< "Expected [PREEMPTED], but goal state is [" << client->getState().toString() << "]";
}
void spinThread()
{
ros::NodeHandle nh;
ros::spin();
}
int main(int argc, char **argv){
testing::InitGoogleTest(&argc, argv);
ros::init(argc, argv, "simple_client_test");
client = std::unique_ptr<SimpleActionClient<TestAction>>(new SimpleActionClient<TestAction>("/my_action", true));
boost::thread spin_thread(&spinThread);
int result = RUN_ALL_TESTS();
ros::shutdown();
spin_thread.join();
return result;
}
The error message (regardless of whether or not the tests succeed):
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::lock_error> >'
what(): boost: mutex lock failed in pthread_mutex_lock: Invalid argument
I have been meaning to look into this error for awhile, it happens on every ros test that we run.
try transposing the line ros::shutdown() with spin_thread.join(). I think these are issues where an object is destroyed in one thread while another thread is using it. In this case I think this might be the ros::NodeHandle existing after ros::shutdown()
The problem is that your unique_ptr never goes out of scope because it is global. Put "client.reset(nullptr);" before ros::shutdown().