[英]Destroying a shared_ptr member variable in the class destructor using a thread
[英]Using member shared_ptr from a member callback function running in different thread (ROS topic subscription)
我不完全確定如何最好地命名這個問題,因為我不完全確定問題的本質是什么(我猜“如何修復段錯誤”不是一個好標題)。
情況是,我寫了這段代碼:
template <typename T> class LatchedSubscriber {
private:
ros::Subscriber sub;
std::shared_ptr<T> last_received_msg;
std::shared_ptr<std::mutex> mutex;
int test;
void callback(T msg) {
std::shared_ptr<std::mutex> thread_local_mutex = mutex;
std::shared_ptr<T> thread_local_msg = last_received_msg;
if (!thread_local_mutex) {
ROS_INFO("Mutex pointer is null in callback");
}
if (!thread_local_msg) {
ROS_INFO("lrm: pointer is null in callback");
}
ROS_INFO("Test is %d", test);
std::lock_guard<std::mutex> guard(*thread_local_mutex);
*thread_local_msg = msg;
}
public:
LatchedSubscriber() {
last_received_msg = std::make_shared<T>();
mutex = std::make_shared<std::mutex>();
test = 42;
if (!mutex) {
ROS_INFO("Mutex pointer is null in constructor");
}
else {
ROS_INFO("Mutex pointer is not null in constructor");
}
}
void start(ros::NodeHandle &nh, const std::string &topic) {
sub = nh.subscribe(topic, 1000, &LatchedSubscriber<T>::callback, this);
}
T get_last_msg() {
std::lock_guard<std::mutex> guard(*mutex);
return *last_received_msg;
}
};
本質上它所做的是訂閱一個主題(頻道),這意味着每次消息到達時都會調用一個回調 function。 這個 class 的工作是存儲最后收到的消息,以便 class 的用戶可以隨時訪問它。
在構造函數中,我為消息分配了一個 shared_ptr,並為一個互斥鎖分配了對這個消息的同步訪問。 這里使用堆 memory 的原因是可以復制LatchedSubscriber
並且仍然可以讀取相同的鎖存消息。 ( Subscriber
已經實現了這種行為,復制它不會做任何事情,除了一旦最后一個實例超出范圍,回調就會停止調用)。
問題基本上是代碼段錯誤。 我很確定這是因為我的共享指針在回調 function 中變為null
,盡管在構造函數中不是 null。
ROS_INFO
調用打印:
Mutex pointer is not null in constructor
Mutex pointer is null in callback
lrm: pointer is null in callback
Test is 42
我不明白這怎么會發生。 我想我對共享指針、ros 主題訂閱或兩者都有誤解。
我做過的事情:
this
指針指向另一個線程可能是不好的,所以我將它移到了一個start
function 中,它在 object 構建后調用。shared_ptr
的線程安全性似乎有很多方面。 起初我在回調中直接使用了mutex
和last_received_msg
。 現在我已將它們復制到局部變量中,希望這會有所幫助。 但這似乎沒有什么不同。我想我已經找到了問題所在。
訂閱時,我將this
指針與回調一起傳遞給訂閱 function。 如果LatchedSubscriber
曾經被復制並且原始的被刪除,那么this
指針就會變得無效,但是sub
仍然存在,所以回調會繼續被調用。
我不認為這發生在我的代碼中的任何地方,但LatcedSubscriber
存儲為 object 中的成員,該成員由唯一指針擁有。 看起來make_unique
可能會在內部進行一些復制? 在任何情況下,使用this
指針進行回調都是錯誤的。
我最終改為執行以下操作
void start(ros::NodeHandle &nh, const std::string &topic) {
auto l_mutex = mutex;
auto l_last_received_msg = last_received_msg;
boost::function<void(const T)> callback =
[l_mutex, l_last_received_msg](const T msg) {
std::lock_guard<std::mutex> guard(*l_mutex);
*l_last_received_msg = msg;
};
sub = nh.subscribe<T>(topic, 1000, callback);
}
這樣,兩個智能指針的副本將與回調一起使用。
將閉包分配給boost::function<void(const T)>
類型的變量似乎是必要的。 可能是由於subscribe
function 的方式。
這似乎已經解決了這個問題。 我可能還會將訂閱再次移入構造函數並擺脫start
方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.