Resetting a shared pointer captured in a lambda function - c++

(I'm very unsure about the phrasing of the question title. I'm hoping it's not misleading because I really don't know how to summarize this. But I'll try to explain my problem as well as I can.)
In a project, there is something like this (written from memory and simplified):
Class A {
private:
boost::weak_ptr<SomeClassB> b;
public:
static boost::shared_ptr<SomeClassB> StopSomeProcesses () {
boost::shared_ptr<SomeClassB> temp (new SomeClassB());
b = temp;
return temp;
}
}
Now in another project, I need to do something similar to the following:
boost::shared_ptr<SomeClassB> obj;
void someFunction () {
obj = A::StopSomeProcesses();
auto callback = [](){
//some other stuff here
obj.reset();
};
NamespaceFromYetAnotherProject::DoSomething(callback);
}
What this basically does is while b holds a valid object from A::StopSomeProcesses, as the name implies, some processes will be stopped. In this case, the processes are stopped while DoSomething is executed. At the end, DoSomething will call callback where obj is reset and the stopped processes can now finally continue.
I've done this and it works. However, as much as possible, I'd like to avoid using global variables. I tried doing the following:
void someFunction () {
boost::shared_ptr<SomeClassB> obj;
obj = A::StopSomeProcesses();
auto callback = [&obj](){
//some other stuff here
obj.reset();
};
NamespaceFromYetAnotherProject::DoSomething(callback);
}
The above code works. But I'm not sure if I was already in "undefined behavior" territory and just got lucky. Doesn't obj's scope end already? Or does the fact that the lambda was passed as an argument help extend its "life"? If this is safe to do, is that safety lost if callback is run on another thread?
I also tried doing this:
void someFunction () {
boost::shared_ptr<SomeClassB> obj;
obj = A::StopSomeProcesses();
auto callback = [obj](){
//some other stuff here
boost::shared_ptr<SomeClassB> tempObj (new SomeClassB(*obj));
tempObj.reset();
};
NamespaceFromYetAnotherProject::DoSomething(callback);
}
But this was something I tried randomly. I wrote it while completely focused on just deleting the object held by the shared pointer. It worked, but I'm not even sure if it's just roundabout or even valid.
Are these attempts going anywhere? Or am I completely going the wrong way? Or should I just stick to using a global variable? Would appreciate any help on how to go about this problem. Thanks!

You are using a shared_ptr and StopSomeProcesses will internally allocate the memory it points to. Pointers are passed by value so the lifetime of obj is irelevant. Every function call makes a new copy of it as does the binding in the lambda. What matters is what the pointer points too and that was allocated with new and lives on.

Related

Using member shared_ptr from a member callback function running in different thread (ROS topic subscription)

I am not completely sure how to best title this question since I am not completely sure what the nature of the problem actually is (I guess "how fix segfault" is not a good title).
The situation is, I have written this code:
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;
}
};
Essentially what it is doing is subscribing to a topic (channel), meaning that a callback function is called each time a message arrives. The job of this class is to store the last received message so the user of the class can always access it.
In the constructor I allocate a shared_ptr to the message and for a mutex to synchronize access to this message. The reason for using heap memory here is so the LatchedSubscriber can be copied and the same latched message can still be read. (the Subscriber already implements this kind of behavior where copying it doesn't do anything except for the fact that the callback stops being called once the last instance goes out of scope).
The problem is basically that the code segfaults. I am pretty sure the reason for this is that my shared pointers become null in the callback function, despite not being null in the constructor.
The ROS_INFO calls print:
Mutex pointer is not null in constructor
Mutex pointer is null in callback
lrm: pointer is null in callback
Test is 42
I don't understand how this can happen. I guess I have either misunderstood something about shared pointers, ros topic subscriptions, or both.
Things I have done:
At first I had the subscribe call happening in the constructor. I think giving the this pointer to another thread before the constructor has returned can be bad, so I moved this into a start function which is called after the object has been constructed.
There are many aspects to the thread safety of shared_ptrs it seems. At first I used mutex and last_received_msg directly in the callback. Now I have copied them into local variables hoping this would help. But it doesn't seem to make a difference.
I have added a local integer variable. I can read the integer I assigned to this variable in the constructor from the callback. Just a sanity check to make sure that the callback is actually called on an instance created by my constructor.
I think I have figured out the problem.
When subscribing I am passing the this pointer to the subscribe function along with the callback. If the LatchedSubscriber is ever copied and the original deleted, that this pointer becomes invalid, but the sub still exists so the callback keeps being called.
I didn't think this happened anywhere in my code, but the LatcedSubscriber was stored as a member inside an object which was owned by a unique pointer. It looks like make_unique might be doing some copying internally? In any case it is wrong to use the this pointer for the callback.
I ended up doing the following instead
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);
}
This way copies of the two smart pointers are used with the callback instead.
Assigning the closure to a variable of type boost::function<void(const T)> seems to be necessary. Probably due to the way the subscribe function is.
This appears to have fixed the issue. I might also move the subscription into the constructor again and get rid of the start method.

c++ class method thread [duplicate]

This question already has answers here:
Start thread with member function
(5 answers)
Closed 6 years ago.
i have a class that has a method that needs to be running continuously but also be able to receive input from user. So i thought i would make the method run separately using a thread.
the code looks something like this(just the backbone):
class SystemManager
{
private:
int command;
bool commandAcK;
bool running;
//other vars
public:
SystemManager()
{
//initialisation
}
void runningAlgorithm()
{
while (running)
{
if (commandAcK)
{
//solve command
}
//run algorithm
//print results
}
}
void readCmd()
{
cin >> command;
commandAcK = true;
}
};
int main()
{
SystemManager *SM = new SystemManager;
thread tRunning = SM->runningAlgorithm();
}
now the errors look like this:
no suitable constructor exists to convert from "void" to "std::thread"
Error C2440 'initializing': cannot convert from 'void' to 'std::thread'
i have found a new method and it doesn't give me any errors
std::thread tRunning(&SystemManager::runningAlgorithm, SystemManager());
the first thing i don't understand is that this method doesn't use an instance of the class just the generic function. How can i link it to a specific instance? I need it so it can read the values of the variables.
Secondly what does "&" in front of SystemManager do?
(&SystemManager::runningAlgorithm)
Thirdly is there a better way of doing it? Do you have any ideas?
Thank you in advance.
std::thread tRunning(&SystemManager::runningAlgorithm, SystemManager()); does use an instance of your class. The instance it uses is SystemManager() which is a temporary and only available to the thread. If you need to share the instance then you need to create one yourself and pass it by reference to the thread like
SystemManager sys_manager;
std::thread tRunning([&](){sys_manager.runningAlgorithm();});
And now your call site and your thread have the same instance.
Also note that command and commandAck need to be protected by some sort of synchronization since you can write to them while reading causing a data race and subsequently undefined behavior. Using std::atmoic should work for you.
The constructor for std::thread accepts a functor, and optionally it's arguments. A functor is anything that can be "called" using operator().
Then it starts a thread and inside that thread calls your functor.
std::thread tRunning(&SystemManager::runningAlgorithm, SystemManager());
This will call the member function SystemManager::runningAlgorithm, passing in the only argument being this (SystemManager() creates a temporary instance).
Remember that member functions always accept this as the first argument.
&SystemManager::runningAlgorithm returns the address of the member function runningAlgorithm from the class SystemManager.
In modern C++ this code can be simplified (i.e. made more readable) with a lambda:
std::thread tRunning([]{ SystemManager().runningAlgorithm(); });
The line
thread tRunning = SM->runningAlgorithm();
takes the result of running SM->runningAlgorithm() (a void), and tries to construct a thread from it. If you look at the relevant constructor, though, you can see it needs a function-like argument (with possibly arguments).
One way of running it is through a lambda function:
thread tRunning(
[SM](){SM->runningAlgorithm();});
Two other things to note:
You should join the thread before its destructor is called, in this case:
tRunning.join();
You have a (short lived) memory leak. Why not just create it on the stack?
SystemManager SM;
thread tRunning(
[&](){SM.runningAlgorithm();});
tRunning.join();
Uhm... I guesss you need to study some of the basic concepts of c++, before going multithread.
However... In your code,
thread tRunning = SM->runningAlgorithm();
tries to put the result of your function (that is void... ) inside a variable of type thread... Non likely to be right.
Instead, your second code takes 2 arguments:
std::thread tRunning(
&SystemManager::runningAlgorithm, //a pointer to a method (a pointer to the code of your function, and that is why you use the "&", even though you could have left that out)
SystemManager()); // An instance of the value, built on the stack.
I guest that you are confused by the lack of the word "new" (coming from higher level language?), but that's how it works here:
SystemManager sm = SystemManager(); // <- variable created on the stack, will be automatically destroyed when out of scope
SystemManager *psm = new SystemManager(); // Created in the heap, while in the stack remains just a pointer to it.
//You will need to delete it when done with :
delete psm;
To answer the question
How can i link it to a specific instance? I need it so it can read the values of the variables.
You can do:
int main()
{
SystemManager SM; // = SystemManager(); // <- this is not needed
std::thread tRunning(SystemManager::runningAlgorithm, SM);
// Access SM as you need
// REMEMBER TO CLOSE & JOIN THE THREAD!
tRunning.join();
}
I still think you should first get used to the underlying concepts or it will be really difficult to go on.

Pass an object to another thread with AfxBeginThread

My program has a callback function which is called to handle notifications that are received in the form of objects. Because we can handle hundreds a second, this callback function handles the events by spawning a separate thread to handle each one. This is the callback function:
void _OnEvent(LPCTSTR eventID, CNotification cNotificaton) {
if (_pActiveDoc) {
Param_Event* p = new Param_Event;
p->pDoc = _pActiveDoc;
p->lpszEventID = eventID;
p->cNotification = cNotification;
AfxBeginThread(ProcessEvent,p);
}
}
My query comes from the fact that is passed to the callback method is initially created on the stack, and is therefore (according to my understanding) limited to the scope of the calling method:
void CallingMethod(CString strEventID) {
CNotification cNotification;
// Fill in the details of the notification
_OnEvent(strEventID,cNotification);
}
CNotification has a full copy constructor, and since the Param_Event object is created on the heap, my belief was that this would allow the original CNotification object to fall out of scope safely, with the spawned thread working from its own "private" CNotification object that exists until the Param_Event object is deleted with delete. The fact is, however, that we are getting (rare but occasional) crashing, and I am wondering if perhaps my belief here is incorrect: is it possible that the spawned thread is still accessing the original object somehow? If this was the case, this would explain the crashing by the rare occurrence of the object both falling out of scope and being overwritten in memory, thus creating a memory access exception.
Could I be right? Is there anything actually wrong with the method I am using? Would it be safer create the notification object on the heap initially (this would mean changing a lot of our code), or building a new object on the heap to pass to the spawned thread?
For reference, here is my ProcessEvent() method:
Param_TelephoneEvent *p = (Param_TelephoneEvent*)lParam;
p->pDoc->OnTelephoneEvent(p->lpszEventID,p->cNotification);
delete p;
return 0;
All advice welcome. Thanks in advance!
Edit: Copy constructor:
CNotification& CNotification::operator=(const CNotification &rhs)
{
m_eamspeMostRecentEvent = rhs.m_eamspeMostRecentEvent;
m_eamtcsCallStatusAtEvent = rhs.m_eamtcsCallStatusAtEvent;
m_bInbound = rhs.m_bInbound;
strcpy(m_tcExtension , rhs.m_tcExtension);
strcpy(m_tcNumber, rhs.m_tcNumber);
strcpy(m_tcName,rhs.m_tcName);
strcpy(m_tcDDI,rhs.m_tcDDI);
strcpy(m_tcCallID,rhs.m_tcCallID);
strcpy(m_tcInterTelEvent,rhs.m_tcInterTelEvent);
m_dTimestamp = rhs.m_dTimestamp;
m_dStartTime = rhs.m_dStartTime;
m_nCallID = rhs.m_nCallID;
return *this;
}

C++ delete in daughter thread

It is my understanding that the function called when starting a thread inside an object should not be a class member. The best approach seems to be to launch a friend function, which gets you access back into your object.
In general, the member function (and therefore, the parent thread) that launched the daughter thread can continue or it can return. In every case where I use this technique, I let the launcher method just return to the app in the parent thread that called it; something like Qt threads.
When the daughter thread has finished its work, the final thing it does is return into the friend function which itself returns to something waiting to catch its return (pthread_koin or WaitForSingleEvent) or, if there is no catcher, I guess you'd say it returns to nowhere.
So, here is the question. If there is no catcher for the return from the friend function, that is, the parent thread is not in a member function, can I safely destroy the object that launched the child thread from the friend function?
EDIT --------------------------------------------------------------------------
Obvious from the responses, I need an example. We'll go for Windows. Not that different from Linux. I have left out lots of stuff, the class definition, etc.
Main creates so, a SomeObject on the heap.
Main calls so->run() and goes off to do other stuff.
Run() launches the daughter thread that runs SomeFriend().
SomeFriend() calls so->Worker() (that == so)
Worker() does whatever and returns to SomeFriend().
CAN I DELETE so HERE? i.e. delete that <<<=== the subject of this question.
SomeFriend() returns terminating the daughter thread.
//=================================================================
int main( int argc, char** argv )
{
SomeObject* so = new SomeObject();
so->run();
while(1)
{
DoOtherTasks(); // but don't exit!
}
return 0;
//=================================================================
void SomeObject::run();
(
volatile DWORD ThreadId; // Thread ID
HANDLE threadHandle;
try
{
threadHandle = CreateThread(
NULL, // default security attributes
0, // set stack size: default = 0
(LPTHREAD_START_ROUTINE)(SomeFriend),
(LPVOID*)this, // func args: this
0, // default creation flags
(LPDWORD)(&ThreadId) // ptr to thread identifier
);
}
catch ( ... )
{ throw; }
} // launches the thread and returns.
//=================================================================
void* SomeFriend( void* thisPtr ) // is a friend of SomeObject
{
SomeObject* that ((SomeObject*)thisPtr);
that->Worker();
// HERE IS WHERE THE QUESTION IS TALKING ABOUT
// CAN I DO THIS SAFELY?
delete that;
return (void*)NULL;
}
//=================================================================
void SomeObject::Worker() // remember, this is run in the daughter thread.
{
// whatever
return (void*)NULL;
}
To answer your edited question, yes you can delete that; However, remember that main() or any functions it calls might not have a valid so at any point in its logic after so->run() was called because of the way the thread scheduler may have scheduled the threads.
Think of the thread as "owning" so after you've called so->run(). main() and its stack descendants should never touch so again without guarded logic.
Yes.
Your memory management code should be thread-safe already (or threading would be dangerous to start with!) so the free() itself should be fine. The destruction is fine as well, as long as you keep in mind that nobody else may have a reference to this object as they will be pointing to a destructed object.
The reason that people say that it should not be a class member is that member functions have a typically hidden pointer that's also treated differently on a byte level from other parameters, so you can't just call it as a normal function with an extra parameter. This makes it typically incompatible with the pthread_create and CreateThreadEx functions that have a specific calling convention they want. That's why you have a bouncer static / global / friend function that does this calling convention conversion for you (and probably so transparently that you don't notice it yourself).
There's no inherent reason for not launching a member function as the top-level function in a thread. C++11 handles it just fine:
struct S {
void f();
};
S s;
int main() {
std::thread thr(&S::f, s);
thr.join();
return 0;
}

Self destructing objects

Just wondering whether an object can self-destruct.
Consider this situation.
An object that extends a thread object.
Session : Thread
{
Session() {}
~Session() {}
ThreadMain()
{
while(!done){
/* do stuff ... */
...
// something sets done = true;
}
~Client();
}
};
void start_session()
{
Session* c = new Session();
Session->Start();
// when I exit here, I've lost my reference to s. But if the object
// self destructs when done, I don't need it right?
}
Somewhere along the way, we have a function called start_session which starts a session.
Eventually the session ends.
In the conventional approach I would have to have some sort of list of Session objects
placed in that list after calling new.
To clean up the objects I'd have to figure out which ones are finished and call a cleanup
function later.
I thought it might make more sense if they could just clean up themselves. Can that be done?
Why? why not? better approaches?
you can do "delete this" when the session loop exits
but see https://isocpp.org/wiki/faq/freestore-mgmt