I have a C++11 function making calls against a legacy C function. I thought it would be good to create worker threads(using std::thread that will then pass variables to the C function. However, it would seem that if the thread waits too long to execute, that the pointers then no longer point to valid places in memory.
Example(shorted for brevity/readability, and obviously not production code but recreates the issue):
//The C function
void c_func(const char* str1, const char* str2, const char* str3){
printf("My strings str1: %s, str2: %s, str3: %s\n", str1, str2, str3);
}
...
//C++ calling the function from numerous threads
std::vector<std::thread> threads;
std::vector<std::vector<std::string>> bar;
...
for (auto const& foo : bar)
{
threads.push_back(std::thread(c_func, foo[0].c_str(), foo[1].c_str(), (foo[0] + foo[1]).c_str()));
}
The printout will printout garbage at different random times. After some experimenting, I noticed that this does not happen when I change the "C function" to use std::string instead of const char*. However, that change would mean a ton of re-writes on legacy code...which I would rather not do...
Is there a way to allow this type of multithreaded call without the pointers pointing to garbage if the thread is not executed in time? Or am I stuck with rewriting legacy code to move it to C++...
Because the c_str() doesn't prevent the string from being cleaned up. After the function returns and bar is cleaned up then the foo strings are also cleaned up which may be before the thread starts.
You should pass the actual std::string (possibly to a wrapper that then extract the char* before calling func) or otherwise ensure the strings don't get cleaned up before you join()ed all the threads.
The core issue with threading here is that the parent thread will do stuff with the memory at the other end of those pointers, making them invalid.
What you need to do is pass std::string into each thread. Not a reference, not a pointer, but a copy. Now each thread owns its own copy of the string, which will be automatically cleaned up via the magic of the stack and destructors.
Now you can call c_str() on each string copy to get a pointer that will be valid for that thread and not cleaned up in a different scope.
Related
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.
Preface:
When I'm typing out new code, I declare my functions as pass-by-reference-to-const without thinking (out of habit), and sometimes have to go back and change it when I realize it's not what I meant to do.
I'm writing a worker-thread class that runs indefinitely, and is fed strings (from another thread) for processing. When I realized that I had declared the function as pass-by-ref, I went back to change it to pass-by-value, for thread-safety.
But, since I would like to squeeze out as much speed and efficiency as possible, I stopped myself to first explore the options. I wrote a little test routine - and discovered that I'm fuzzy on some key concepts.
To the point: I first wrote the test code below without the commented line:
// std::thread _thread(workthread, move(str)); // Thread safe (contents are moved)
So, ignore that line for now.
#include <iostream>
#include <string>
#include <thread>
#include <chrono>
#include <atomic>
std::atomic<bool> done = false;
void workthread(const std::string &str)
{
std::string &s = const_cast<std::string &>(str);
s = "Work Thread"; // test to see if this changes the main thread's string
}
// This just watches for <enter> on the keyboard in order to quit the program.
void quitmonitor()
{
std::getchar();
done = true;
}
int main(int argc, char **argv)
{
std::thread _monitor(quitmonitor);
std::string str("Main Thread");
std::thread _thread([&]{workthread(std::move(str));}); // Not thread safe (address is copied)
// std::thread _thread(workthread, move(str)); // Thread safe (contents are moved)
const auto minlen(str.length());
const auto maxlen(minlen ? minlen*2 : 15);
bool going_up = true;
while (!done) {
if (going_up)
str.push_back('+');
else
str.pop_back();
if (str.length() == minlen)
going_up = true;
if (str.length() == maxlen)
going_up = false;
std::cout << str << "\n";
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
_thread.join();
_monitor.join();
}
All main() does is create a string "Main Thread", and moves it to the thread function void workthread(const std::string &). The thread function then changes the lvalue's data and returns. The main continues on to a loop which just prints its local string to console (with some additional eye-candy to make it easy to see things happening on the screen). Here's the output:
So, it didn't work as I had expected. I had thought that the thread instantiation would "move" str to the thread function (emptying its data in the process), and the thread's assignment to the function's string argument would have no affect. But clearly it did, as demonstrated by the output.
This must have something to do with the fact that I constructed _thread with a lambda:
std::thread _thread([&]{workthread(std::move(str));}); // Not thread safe (address is copied)
So then I changed the instantiation to:
std::thread _thread(workthread, move(str)); // Thread safe (contents are moved)
and it worked as expected:
Q1: Why do the two instances, lambda vs bind(I guess?), yield different results?
Q2: Am I actually buying myself anything by declaring this as pass-by-reference?
I should note that the actual program is quite time critical, and is intended to run uninterrupted for years on a dedicated server. I'm trying to make the software as low-overhead as possible, to ensure that it can stay in sync (with an external clock), and not accumulate time errors.
std::thread _thread([&]{workthread(std::move(str));});
When _thread is created, it calls your lambda function, which calls workthread(std::move(str)). Note that std::move doesn't actually do anything; it's just a cast to rvalue reference. You never move from str, you just cast the reference to a std::string& in a roundabout way and assign to it.
This also means that you have a data race on str because you have unsynchronized access between the main thread and _thread.
This code moved from the string, though:
std::thread _thread(workthread, move(str));
If you look at std::thread's constructor (it's (3) on that list), you'll see that it "copies" the arguments to the function call; it calls roughly:
workthread(decay_copy(std::move(str)))
This decay_copy actually does move from the string, as it returns by value:
template <class T>
std::decay_t<T> decay_copy(T&& v) { return std::forward<T>(v); }
This is why you see str as being moved from. However, your program is actually relying on unspecified behavior, as – after moving from a std::string – the string is left in a "valid but unspecified state" (std::string's move constructor and move assignment operator). You can't expect str to be an empty string after it's been moved from.
What is the safe / best way to send a CString through PostMessage, from a thread ?
To create CString on heap and clean up when the receiver get this CString ?
Solution 1: In thread:
CString* pError = new CString(_T("Unknown error"));
::PostMessage(...(LPARAM)pError);
and in main thread, somewhere in GUI:
CString* pError = (CString*)lParam;
GetDocument()->DoSomething(*pError);
delete pError;
Solution 2:
Or, to keep CString object as member variable inside of CThread class ?
class CPlanThread : public CThread [: public CObject]
{
public:
DECLARE_DYNAMIC(CPlanThread)
...
protected:
CString* m_pMessage;
};
and
CPlanThread::CPlanThread()
:m_pMessage(NULL)
{
m_pMessage = new CString(_T(""));
}
CPlanThread::~CPlanThread()
{
if(NULL != m_pMessage)
delete m_pMessage;
}
and somewhere in thread:
::PostMessage(m_hWndMain, WMU_NOTIFYTHREAD, 0, (LPARAM)m_pMessage);
and in main thread, somewhere in GUI:
CString* pError = (CString*)lParam;
GetDocument()->DoSomething(*pError);
Both of the above solutions are safe ? Kindly thank you for any explanation.
The first option is the safer alternative.* The only reason, why this could result in a resource leak is, if the call to ::PostMessage fails, and you aren't cleaning up in the sender. Note, that this does not lead to a crash.
The second alternative creates a race condition, since you are holding on to a pointer, whose ownership you meant to transfer. If the GUI thread tries access the string after the thread objects has been destroyed, you are accessing random memory. This can lead to an immediate crash, if you are lucky.
Depending on your specific use case, you might want to consider using a third alternative: Using a CString object with automatic storage duration and thread synchronization through message-sending, e.g.:
CStringW err( L"Unknown error" );
::SendMessage( ..., (LPARAM)&err );
The receiving thread can use the string object for as long as it is in its message handler, and the sender will automatically clean up the resource.
* That is assuming, that both threads are implemented in the same module. Make sure to read Potential Errors Passing CRT Objects Across DLL Boundaries in case they aren't.
I would always prefer to store things in a member variable (which means there is an object responsible for cleaning them up). However, see an important caveat below. I would also prefer to hold a CString by value, rather than by pointer. Storing the pointer just makes another bit of memory you've got to manage. So:
class CPlanThread : public CThread [: public CObject]
{
public:
DECLARE_DYNAMIC(CPlanThread)
...
protected:
CString m_Message;
};
and
CPlanThread::CPlanThread()
:m_Message(L"")
{
}
CPlanThread::~CPlanThread()
{
}
and then
::PostMessage(m_hWndMain, WMU_NOTIFYTHREAD, 0, (LPARAM)&m_Message);
Note that this approach means you don't need to do anything in the destructor, and the constructor can initialize the variable (actually, you should have used initialization on the pointer).
I have removed the _T() macro. It's a really bad idea, unless you actually build versions of the software with both types of character (which doubles your testing effort for no benefit). Just get used to writing your literals with a leading 'L'.
Final comment, there is no point testing if a pointer is nullptr before deleting it - delete does that check anyway.
Important Caveat
This approach means you need to make sure that the CPlanThread object exists until after the message is processed - but you had to do that with the pointer member anyway.
If you can't ensure that lifetime, but you can just use string literals, then post a const wchar_t* and you don't have to manage lifetimes.
If you can't ensure the lifetime is long enough, and you can't just use literals, then you will have to use the new/delete approach.
I am writing a function for logging messages .
I will be calling this print function from different threads .
My code is as follows :
MyLog::printLog(const char* s)
{
std::string myline(s);
//m_Mutex is class member and there will be only object for this class
// shared by all threads
int ret = pthread_mutex_lock(&m_Mutex);
if ( ret != 0 )
{
std::cout<<" trying to lock same mutex char* "<<std::endl;
}
//code to log message in File
pthread_mutex_unlock(&m_Mutex);
}
My question is if above function is called from different threads with argument like "from thread1" , "from thread 2" ,... will there be any chance const char *s will be jumbled up printing wrong values .?
I hope my question is clear .
Your function will work as you expect, since myline is a local variable (each thread has its own stack, so would have its own instance of myline)
If you're calling this function from different threads, and any changes you make to your argument const char* s are protected by your mutex m_Mutex then you'll be just fine and nothing will be jumbled.
EDIT
Actually, each call to this function will have it's own stack when called from a different thread, and seeing that it const char* you cannot change your argument, so there's no need to protect it with a mutex.
Your variable s is a variable local to the thread it's being called in, and it's const.
Then copying into the local variable myline is definitely not going to mess with anything, cause each thread has it's call stack, on which lives an instance of myline when this function is called, which is totally separate and independent of any other thread.
It depends on how you are calling the printLog function. If the string whose address you pass to the function gets mutated by a different thread, then you may not see a consistent view of it inside the log function. If you pass in a pointer to an immutable string, like a literal for example, then you're fine, though.
Here's an example that's fine:
void from_thread_one()
{
MyLog::printLog("Hello World"); // immutable string
}
void from_thread_two()
{
MyLog::printLog("Another text"); // ditto
}
On the other hand, here's an example that's not OK and has a race:
char globalString[] = "This is a really long string";
void from_thread_one()
{
globalString[5] = 'A';
MyLog::printLog(globalString);
}
void from_thread_two()
{
globalString[8] = 'Q';
MyLog::printLog(globalString);
}
In this setting, you are making a copy of the string (via std::string myline(s);) while the contents of the array pointed to by s can simultaneously be changed in the other thread. In this scenario, dereferencing the char pointer has to happen inside the critical section as well.
The fundamental problem with your setup is that the raw char pointer has no implicit semantics that tell the user which behaviour is acceptable and which isn't. Had you passed in an actual std::string by value, you would have removed the uncertainty about synchronising access to the string from your printLog function and moved the responsibility entirely into the caller.
I have a program that processes neural spike data that is broadcast in UDP packets on a local network.
My current program has two threads a UI thread and a worker thread. The worker thread simply listens for data packets, parses them and makes them available to the UI thread for display and processing. My current implementation works just fine. However for a variety of reasons I'm trying to re-write the program in C++ using an Object Oriented approach.
The current working program initialized the 2nd thread with:
pthread_t netThread;
net = NetCom::initUdpRx(host,port);
pthread_create(&netThread, NULL, getNetSpike, (void *)NULL);
Here is the getNetSpike function that is called by the new thread:
void *getNetSpike(void *ptr){
while(true)
{
spike_net_t s;
NetCom::rxSpike(net, &s);
spikeBuff[writeIdx] = s;
writeIdx = incrementIdx(writeIdx);
nSpikes+=1;
totalSpikesRead++;
}
}
Now in my new OO version of the program I setup the 2nd thread in much the same way:
void SpikePlot::initNetworkRxThread(){
pthread_t netThread;
net = NetCom::initUdpRx(host,port);
pthread_create(&netThread, NULL, networkThreadFunc, this);
}
However, because pthead_create takes a pointer to a void function and not a pointer to an object's member method I needed to create this simple function that wraps the SpikePlot.getNetworSpikePacket() method
void *networkThreadFunc(void *ptr){
SpikePlot *sp = reinterpret_cast<SpikePlot *>(ptr);
while(true)
{
sp->getNetworkSpikePacket();
}
}
Which then calls the getNetworkSpikePacket() method:
void SpikePlot::getNetworkSpikePacket(){
spike_net_t s;
NetCom::rxSpike(net, &s);
spikeBuff[writeIdx] = s; // <--- SegFault/BusError occurs on this line
writeIdx = incrementIdx(writeIdx);
nSpikes+=1;
totalSpikesRead++;
}
The code for the two implementations is nearly identical but the 2nd implementation (OO version) crashes with a SegFault or BusError after the first packet that is read. Using printf I've narrowed down which line is causing the error:
spikeBuff[writeIdx] = s;
and for the life of me I can't figure out why its causing my program to crash.
What am I doing wrong here?
Update:
I define spikeBuff as a private member of the class:
class SpikePlot{
private:
static int const MAX_SPIKE_BUFF_SIZE = 50;
spike_net_t spikeBuff[MAX_SPIKE_BUFF_SIZE];
....
}
Then in the SpikePlot constructor I call:
bzero(&spikeBuff, sizeof(spikeBuff));
and set:
writeIdx =0;
Update 2: Ok something really weird is going on with my index variables. To test their sanity I changed getNetworkSpikePacket to:
void TetrodePlot::getNetworkSpikePacket(){
printf("Before:writeIdx:%d nspikes:%d totSpike:%d\n", writeIdx, nSpikes, totalSpikesRead);
spike_net_t s;
NetCom::rxSpike(net, &s);
// spikeBuff[writeIdx] = s;
writeIdx++;// = incrementIdx(writeIdx);
// if (writeIdx>=MAX_SPIKE_BUFF_SIZE)
// writeIdx = 0;
nSpikes += 1;
totalSpikesRead += 1;
printf("After:writeIdx:%d nspikes:%d totSpike:%d\n\n", writeIdx, nSpikes, totalSpikesRead);
}
And I get the following output to the console:
Before:writeIdx:0 nspikes:0 totSpike:0
After:writeIdx:1 nspikes:32763 totSpike:2053729378
Before:writeIdx:1 nspikes:32763 totSpike:2053729378
After:writeIdx:1 nspikes:0 totSpike:1
Before:writeIdx:1 nspikes:0 totSpike:1
After:writeIdx:32768 nspikes:32768 totSpike:260289889
Before:writeIdx:32768 nspikes:32768 totSpike:260289889
After:writeIdx:32768 nspikes:32768 totSpike:260289890
This method is the only method where I update their values (besides the constructor where I set them to 0). All other uses of these variables are read only.
I'm going to go on a limb here and say all your problems are caused by the zeroing out of the spike_net_t array.
In C++ you must not zero out objects with non-[insert word for 'struct-like' here] members. i.e. if you have an object that contains a complex object (a std string, a vector, etc. etc.) you cannot zero it out, as this destroys the initialization of the object done in the constructor.
This may be wrong but....
You seemed to move the wait loop logic out of the method and into the static wrapper. With nothing holding the worker thread open, perhaps that thread terminates after the first time you wait for a UDP packet, so second time around, sp in the static method now points to an instance that has left scope and been destructed?
Can you try to assert(sp) in the wrapper before trying to call its getNetworkSpikePacket()?
It looks like your reinterpret_cast might be causing some problems. When you call pthread_create, you are passing in "this" which is a SpikePlot*, but inside networkThreadFunc, you are casting it to a TetrodePlot*.
Are SpikePlot and TetrodePlot related? This isn't called out in what you've posted.
If you are allocating the spikeBuff array anywhere then make sure you are allocating sufficient storage so writeIdx is not an out-of-bounds index.
I'd also check that initNetworkRxThread is being called on an allocated instance of spikePlot object (and not on just a declared pointer).