I have unexpected assertions faillures in my code using a checked STL implentation.
After some research, I narrowed down the problem to a push_back in a vector called from a different thread than the one in which the vector was created.
The simplest code to reproduce this problem is :
class SomeClass
{
private:
std::vector<int> theVector;
public:
SomeClass ()
{
theVector.push_back(1); // Ok
}
void add()
{
theVector.push_back(1); // Crash
}
};
The only difference is that SomeClass is instanciated from my main thread, and add is called from another thread. However, there is no concurency issue : in the simplest form of code I used for troubleshooting nobody is reading or writing from this vector except the cases I mentioned above.
Tracing into the push_back code, I noticed that some methods from std::vector like count() or size() return garbage, when it's called from the other thred (method "add"), and correct values when called from the creating thread (in the constructor for example)
Should I conclude that std::vector is not usable in a multithreaded environement ? Or is there a solution for this problem ?
EDIT : removed volatile
EDIT 2 : Do you think it's possible that the problem doesn't lie in multithread ? In my test run, add is called only once (verified using a break point). If I remove the push_back from the constructor, I still crashes. So in the end, even with only one call to a vector's method, in a function called once make the assertion fail. Therefore there can't be concurency, or ... ?
std::vector definitely is usable in a multi-threaded environment, provided you don't access the vector from two threads at once. I do it all the time without trouble.
Since vector isn't the problem, you need to look more closely at your synchronization mechanism, as this is most likely the problem.
I noticed that you marked the vector as volatile. Do you expect that making it volatile will provide synchronization? Because it won't. See here for more information.
EDIT: Originally provided wrong link. This is now fixed. Sorry for confusion.
If you can guarantee that nobody is writing to or reading from the vector when you call push_back, there's no reason that it should fail. You could be dealing with higher-level memory corruption. You should verify that "this" points to a genuine instance of SomeClass, check it's other members, etc.
Most STL implementations are not thread safe. You'll need to use thread synchronization (e.g. mutex) to prevent both threads from stomping on each other while accessing the vector. Basically, what you will need to do is create a class that contains the vector and a mutex and accessor functions that protect the vector for both reading and writing operations.
Whether Standard Library supports multithreading is implementation defined. You have to read documentation for your specific compiler.
Additionaly what you can do is to add some log messages as in the following code:
class SomeClass
{
private:
volatile std::vector<int> theVector;
public:
SomeClass ()
{
std::cout << "SomeClass::SomeClass" << std::endl;
theVector.push_back(1); // Ok
}
~SomeClass ()
{
std::cout << "SomeClass::~SomeClass" << std::endl;
}
void add()
{
std::cout << "SomeClass::add" << std::endl;
theVector.push_back(1);
}
};
Make sure that instance of the SomeClass is still exists when you call add function.
Related
It is well known that std::shared_ptr is not thread safe.
So it is easy to find a lot of crashing code samples in the web with simple programs to illustrate disadvantages of std::shared_ptr.
But I can't find any for the boost::atomic_shared_ptr
Does this mean that I can use boost::atomic_shared_ptr without any fear it can crash my app in the multithreaded environment?
(Of course the boost::atomic_shared_ptr can contain bugs. So I want to know - it is safe "by design" or not.)
You can use shared_pointer with atomic_load/atomic_store anyways ever since C++11, even though it is superseded in c++20:
https://en.cppreference.com/w/cpp/memory/shared_ptr/atomic
I can't find a lot of examples myself, though I used it here: How to use boost::atomic_store with shared_ptr<T> and shared_ptr<const T>?, and here https://github.com/sehe/msghub/blob/std-over-boost/src/msghub.cpp#L25
Regardless of all this, none of this is going to make your code safe, because you'll still be sharing the objects pointed to by ths shared pointer, which makes your code every bit as prone to Data Races as before.
You still need to add proper synchronization to your code.
std::atomicstd::shared_ptr<> is thread-safe but ONLY for reading and writing the value of the pointer itself. It's use does not make all uses of shared_ptr thread-safe.
Consider this:
// using a single writer of data pointed to by foo for simplicity.
// contract: only set values from main thread (for example)
// set values, then call apply_changes when all your parameters
// are correct.
struct Foo
{
void set_valueA(int x);
//...
void set_valueZ(int x);
void apply_changes();
};
// using global data for silplicity, tis could be a member of some class,
// or in any stable memory location in an application.
// More than one thread may reallocate or reset this object, hence the std::atomic.
std::atomic<std::shared_ptr<Foo>> global_ptr;
void some_function()
{
// Set or reset global_ptr attributes
if (!global_ptr)
return;
global_ptr->set_valueA(42); // a bad_alloc exception could
// happen here
// what happens if global_ptr is set or reset
// by another thread in between these two statements?
global_ptr->set_valueB(17); // a bad_alloc exception may occur here.
global_ptr->apply_changes(); // undefined behavior as per contract of Foo
// may happen here.
}
// for this reason, proper usage would be...
void some_function()
{
// Set or reset global_ptr attributes
// since global_ptr is atomic, it is guaranteed that this line will not crash
// and will always return a well-formed shared_ptr. If fact, that's the
// one and only guarantee given by std::atomic<std::shared_ptr<>>.
if (std::shared_ptr<Foo> local_copy = global_ptr)
{
// Note that local_copy is guaranteed to point to the same object until
// end of scope.
local_copy->set_valueA(42);
local_copy->set_valueB(17);
local_copy->apply_changes();
// if global_ptr has changed, then memory will be released when
// exiting scope.
}
}
So, imho, some basic precautions must still be taken when using atomic shared pointers, either for read or write operations on the pointed to data.
Suppose I have some container class like the one below:
class Container {
public:
int const & operator[] (int n) const {
return data[n];
}
private:
std::vector<int> data;
}
I need to access its elements from multiple threads, using overloaded operator [] and passing an object of this class to lambda capture by reference:
Container store;
std::thread t_1([&store]() { /* do something here and read from store */ } );
std::thread t_2([&store]() { /* do something here and read from store */ } );
Will there be some slowdowns because of such design? Is it possible to speedup this part somehow?
Since std::vector's data() lies on the heap anyway, you cannot omit the access there. The only faster way would be to keep the elements on the stacks of the two threads (threads have separate stacks but share heap space), but this is not a possibility here. Thus, I see no optimisations for your case, unless you share your whole implementation and by changing the approach, one may come up with more performant implementation.
I would advise against it, though. That would belong to CodeReview, not StackOverflow.
Lastly, I would like to mention thread safety - I do not see any races here and I believe you specifically made sure that the example does not hint that you may encounter any (by only showing access to reading and not writing to shared resources), but it is still a good idea to check for them. If what you are doing is only reading, no data races will occur.
Derived from this question and related to this question:
If I construct an object in one thread and then convey a reference/pointer to it to another thread, is it thread un-safe for that other thread to access the object without explicit locking/memory-barriers?
// thread 1
Obj obj;
anyLeagalTransferDevice.Send(&obj);
while(1); // never let obj go out of scope
// thread 2
anyLeagalTransferDevice.Get()->SomeFn();
Alternatively: is there any legal way to convey data between threads that doesn't enforce memory ordering with regards to everything else the thread has touched? From a hardware standpoint I don't see any reason it shouldn't be possible.
To clarify; the question is with regards to cache coherency, memory ordering and whatnot. Can Thread 2 get and use the pointer before Thread 2's view of memory includes the writes involved in constructing obj? To miss-quote Alexandrescu(?) "Could a malicious CPU designer and compiler writer collude to build a standard conforming system that make that break?"
Reasoning about thread-safety can be difficult, and I am no expert on the C++11 memory model. Fortunately, however, your example is very simple. I rewrite the example, because the constructor is irrelevant.
Simplified Example
Question: Is the following code correct? Or can the execution result in undefined behavior?
// Legal transfer of pointer to int without data race.
// The receive function blocks until send is called.
void send(int*);
int* receive();
// --- thread A ---
/* A1 */ int* pointer = receive();
/* A2 */ int answer = *pointer;
// --- thread B ---
int answer;
/* B1 */ answer = 42;
/* B2 */ send(&answer);
// wait forever
Answer: There may be a data race on the memory location of answer, and thus the execution results in undefined behavior. See below for details.
Implementation of Data Transfer
Of course, the answer depends on the possible and legal implementations of the functions send and receive. I use the following data-race-free implementation. Note that only a single atomic variable is used, and all memory operations use std::memory_order_relaxed. Basically this means, that these functions do not restrict memory re-orderings.
std::atomic<int*> transfer{nullptr};
void send(int* pointer) {
transfer.store(pointer, std::memory_order_relaxed);
}
int* receive() {
while (transfer.load(std::memory_order_relaxed) == nullptr) { }
return transfer.load(std::memory_order_relaxed);
}
Order of Memory Operations
On multicore systems, a thread can see memory changes in a different order as what other threads see. In addition, both compilers and CPUs may reorder memory operations within a single thread for efficiency - and they do this all the time. Atomic operations with std::memory_order_relaxed do not participate in any synchronization and do not impose any ordering.
In the above example, the compiler is allowed to reorder the operations of thread B, and execute B2 before B1, because the reordering has no effect on the thread itself.
// --- valid execution of operations in thread B ---
int answer;
/* B2 */ send(&answer);
/* B1 */ answer = 42;
// wait forever
Data Race
C++11 defines a data race as follows (N3290 C++11 Draft): "The execution of a program contains a data race if it contains two conflicting actions in different threads, at least one of which is not atomic, and neither happens before the other. Any such data race results in undefined behavior." And the term happens before is defined earlier in the same document.
In the above example, B1 and A2 are conflicting and non-atomic operations, and neither happens before the other. This is obvious, because I have shown in the previous section, that both can happen at the same time.
That's the only thing that matters in C++11. In contrast, the Java Memory Model also tries to define the behavior if there are data races, and it took them almost a decade to come up with a reasonable specification. C++11 didn't make the same mistake.
Further Information
I'm a bit surprised that these basics are not well known. The definitive source of information is the section Multi-threaded executions and data races in the C++11 standard. However, the specification is difficult to understand.
A good starting point are Hans Boehm's talks - e.g. available as online videos:
Threads and Shared Variables in C++11
Getting C++ Threads Right
There are also a lot of other good resources, I have mentioned elsewhere, e.g.:
std::memory_order - cppreference.com
There is no parallel access to the same data, so there is no problem:
Thread 1 starts execution of Obj::Obj().
Thread 1 finishes execution of Obj::Obj().
Thread 1 passes reference to the memory occupied by obj to thread 2.
Thread 1 never does anything else with that memory (soon after, it falls into infinite loop).
Thread 2 picks-up the reference to memory occupied by obj.
Thread 2 presumably does something with it, undisturbed by thread 1 which is still infinitely looping.
The only potential problem is if Send didn't acts as a memory barrier, but then it wouldn't really be a "legal transfer device".
As others have alluded to, the only way in which a constructor is not thread-safe is if something somehow gets a pointer or reference to it before the constructor is finished, and the only way that would occur is if the constructor itself has code that registers the this pointer to some type of container which is shared across threads.
Now in your specific example, Branko Dimitrijevic gave a good complete explanation how your case is fine. But in the general case, I'd say to not use something until the constructor is finished, though I don't think there's anything "special" that doesn't happen until the constructor is finished. By the time it enters the (last) constructor in an inheritance chain, the object is pretty much fully "good to go" with all of its member variables being initialized, etc. So no worse than any other critical section work, but another thread would need to know about it first, and the only way that happens is if you're sharing this in the constructor itself somehow. So only do that as the "last thing" if you are.
It is only safe (sort of) if you wrote both threads, and know the first thread is not accessing it while the second thread is. For example, if the thread constructing it never accesses it after passing the reference/pointer, you would be OK. Otherwise it is thread unsafe. You could change that by making all methods that access data members (read or write) lock memory.
Read this question until now... Still will post my comments:
Static Local Variable
There is a reliable way to construct objects when you are in a multi-thread environment, that is using a static local variable (static local variable-CppCoreGuidelines),
From the above reference: "This is one of the most effective solutions to problems related to initialization order. In a multi-threaded environment the initialization of the static object does not introduce a race condition (unless you carelessly access a shared object from within its constructor)."
Also note from the reference, if the destruction of X involves an operation that needs to be synchronized you can create the object on the heap and synchronize when to call the destructor.
Below is an example I wrote to show the Construct On First Use Idiom, which is basically what the reference talks about.
#include <iostream>
#include <thread>
#include <vector>
class ThreadConstruct
{
public:
ThreadConstruct(int a, float b) : _a{a}, _b{b}
{
std::cout << "ThreadConstruct construct start" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "ThreadConstruct construct end" << std::endl;
}
void get()
{
std::cout << _a << " " << _b << std::endl;
}
private:
int _a;
float _b;
};
struct Factory
{
template<class T, typename ...ARGS>
static T& get(ARGS... args)
{
//thread safe object instantiation
static T instance(std::forward<ARGS>(args)...);
return instance;
}
};
//thread pool
class Threads
{
public:
Threads()
{
for (size_t num_threads = 0; num_threads < 5; ++num_threads) {
thread_pool.emplace_back(&Threads::run, this);
}
}
void run()
{
//thread safe constructor call
ThreadConstruct& thread_construct = Factory::get<ThreadConstruct>(5, 10.1);
thread_construct.get();
}
~Threads()
{
for(auto& x : thread_pool) {
if(x.joinable()) {
x.join();
}
}
}
private:
std::vector<std::thread> thread_pool;
};
int main()
{
Threads thread;
return 0;
}
Output:
ThreadConstruct construct start
ThreadConstruct construct end
5 10.1
5 10.1
5 10.1
5 10.1
5 10.1
This question already has answers here:
How can I determine if a C++ object has been deallocated?
(6 answers)
Closed 4 years ago.
Consider this program:
int main()
{
struct test
{
test() { cout << "Hello\n"; }
~test() { cout << "Goodbye\n"; }
void Speak() { cout << "I say!\n"; }
};
test* MyTest = new test;
delete MyTest;
MyTest->Speak();
system("pause");
}
I was expecting a crash, but instead this happened:
Hello
Goodbye
I say!
I'm guessing this is because when memory is marked as deallocated it isn't physically wiped, and since the code references it straight away the object is still to be found there, wholly intact. The more allocations made before calling Speak() the more likely a crash.
Whatever the reason, this is a problem for my actual, threaded code. Given the above, how can I reliably tell if another thread has deleted an object that the current one wants to access?
There is no platform-independent way of detecting this, without having the other thread(s) set the pointer to NULL after they've deleted the object, preferably inside a critical section, or equivalent.
The simple solution is: design your code so that this can't occur. Don't delete objects that might be needed by other threads. Clear up shared resource only once it's safe.
I was expecting a crash, but instead
this happened:
That is because Speak() is not accessing any members of the class. The compiler does not validate pointers for you, so it calls Speak() like any other function call, passing the (deleted) pointer as the hidden 'this' parameter. Since Speak() does not access that parameter for anything, there is no reason for it to crash.
I was expecting a crash, but instead this happened:
Undefined Behaviour means anything can happen.
Given the above, how can I reliably tell if another thread has deleted an object that the current one wants to access?
How about you set the MyTest pointer to zero (or NULL). That will make it clear to other threads that it's no longer valid. (of course if your other threads have their own pointers pointing to the same memory, well, you've designed things wrong. Don't go deleting memory that other threads may use.)
Also, you absolutely can't count on it working the way it has. That was lucky. Some systems will corrupt memory immediately upon deletion.
Despite it's best to improve the design to avoid access to a deleted object, you can add a debug feature to find the location where you access deleted objects.
Make all methods and the destructor virtual.
Check that your compiler creates an object layout where the pointer to
the vtable is in front of the object
Make the pointer to the vtable invalid in the destructor
This dirty trick causes that all functions calls reads the address where the pointer points to and cause a NULL pointer exception on most systems. Catch the exception in the debugger.
If you hesitate to make all methods virtual, you can also create an abstract base class and inherit from this class. This allows you to remove the virtual function with little effort. Only the destructor needs to be virtual inside the class.
example
struct Itest
{
virtual void Speak() = 0;
virtual void Listen() = 0;
};
struct test : public Itest
{
test() { cout << "Hello\n"; }
virtual ~test() {
cout << "Goodbye\n";
// as the last statement!
*(DWORD*)this = 0; // invalidate vtbl pointer
}
void Speak() { cout << "I say!\n"; }
void Listen() { cout << "I heard\n"; }
};
You might use reference counting in this situation. Any code that dereferences the pointer to the allocated object will increment the counter. When it's done, it decrements. At that time, iff the count hits zero, deletion occurs. As long as all users of the object follow the rules, nobody access the deallocated object.
For multithreading purposes I agree with other answer that it's best to follow design principles that don't lead to code 'hoping' for a condition to be true. From your original example, were you going to catch an exception as a way to tell if the object was deallocated? That is kind of relying on a side effect, even if it was a reliable side effect which it's not, which I only like to use as a last resort.
This is not a reliable way to "test" if something has been deleted elsewhere because you are invoking undefined behavior - that is, it may not throw an exception for you to catch.
Instead, use std::shared_ptr or boost::shared_ptr and count references. You can force a shared_ptr to delete it's contents using shared_ptr::reset(). Then you can check if it was deleted later using shared_ptr::use_count() == 0.
You could use some static and runtime analyzer like valgrind to help you see these things, but it has more to do with the structure of your code and how you use the language.
// Lock on MyTest Here.
test* tmp = MyTest;
MyTest = NULL;
delete tmp;
// Unlock MyTest Here.
if (MyTest != NULL)
MyTest->Speak();
One solution, not the most elegant...
Place mutexes around your list of objects; when you delete an object, mark it as null. When you use an object, check for null. Since access is serialized, you'll have a consistent operation.
Yesterday I read some code of a colleague and came across this:
class a_class
{
public:
a_class() {...}
int some_method(int some_param) {...}
int value_1;
int value_2;
float value_3;
std::vector<some_other_class*> even_more_values;
/* and so on */
}
a_class a_instances[10];
void some_function()
{
do_stuff();
do_more_stuff();
memset(a_instances, 0, 10 * sizeof(a_class)); // <===== WTF?
}
Is that legal (the WTF line, not the public attributes)? To me it smells really, really bad...
The code ran fine when compiled with VC8, but it throws an "unexpected exception" when compiled with VC9 when calling a_instances[0].event_more_values.push_back(whatever), but when accessing any of the other members. Any insights?
EDIT: Changed the memset from memset(&a_instances... to memset(a_instances.... Thanks for pointing it out Eduard.
EDIT2: Removed the ctor's return type. Thanks litb.
Conclusion: Thanks folks, you confirmed my suspicion.
This is a widely accepted method for initialization for C structs.
In C++ it doesn't work ofcourse because you can't assume anything about vectors internal structure. Zeroing it out is very likely to leave it in an illegal state which is why your program crashes.
He uses memset on a non-POD class type. It's invalid, because C++ only allows it for the simplest cases: Where a class doesn't have a user declared constructor, destructor, no virtual functions and several more restrictions. An array of objects of it won't change that fact.
If he removes the vector he is fine with using memset on it though. One note though. Even if it isn't C++, it might still be valid for his compiler - because if the Standard says something has undefined behavior, implementations can do everything they want - including blessing such behavior and saying what happens. In his case, what happens is probably that you apply memset on it, and it would silently clear out any members of the vector. Possible pointers in it, that would point to the allocated memory, will now just contain zero, without it knowing that.
You can recommend him to clear it out using something like this:
...
for(size_t i=0; i < 10; i++)
objects[i].clear();
And write clear using something like:
void clear() {
a_object o;
o.swap(*this);
}
Swapping would just swap the vector of o with the one of *this, and clear out the other variables. Swapping a vector is especially cheap. He of course needs to write a swap function then, that swaps the vector (even_more_values.swap(that.even_more_values)) and the other variables.
I am not sure, but I think the memset would erase internal data of the vector.
When zeroing out a_instances, you also zero out the std_vector within. Which probably allocates a buffer when constructed. Now, when you try to push_back, it sees the pointer to the buffer being NULL (or some other internal member) so it throws an exception.
It's not legitimate if you ask. That's because you can't overload writing via pointers as you can overload assignment operators.
The worst part of it is that if the vector had anything in it, that memory is now lost because the constructor wasn't called.
NEVER over-write a C++ object. EVER. If it was a derived object (and I don't know the specifics of std::vector), this code also over-writes the object's vtable making it crashy as well as corrupted.
Whoever wrote this doesn't understand what objects are and needs you to explain what they are and how they work so that they don't make this kind of mistake in the future.
You shouldn't do memset on C++ objects, because it doesn't call the proper constructor or destructor.
Specifically in this case, the destructor of even_more_values member of all a_instances's elements is not called.
Actually, at least with the members that you listed (before /* and so on */), you don't need to call memset or create any special destructor or clear() function. All these members are deleted automatically by the default destructor.
You should implement a method 'clear' in your class
void clear()
{
value1=0;
value2=0;
value_3=0f;
even_more_values.clear();
}
What you have here might not crash, but it probably won't do what you want either! Zeroing out the vector won't call the destructor for each a_class instance. It will also overwrite the internal data for a_class.even_more_values (so if your push_back() is after the memset() you are likely to get an access violation).
I would do two things differently:
Use std::vector for your storage both in a_class and in some_function().
Write a destructor for a_class that cleans up properly
If you do this, the storage will be managed for you by the compiler automatically.
For instance:
class a_class
{
public:
a_class() {...}
~a_class() { /* make sure that even_more_values gets cleaned up properly */ }
int some_method(int some_param) {...}
int value_1;
int value_2;
float value_3;
std::vector<some_other_class*> even_more_values;
/* and so on */
}
void some_function()
{
std::vector<a_class> a_instances( 10 );
// Pass a_instances into these functions by reference rather than by using
// a global. This is re-entrant and more likely to be thread-safe.
do_stuff( a_instances );
do_more_stuff( a_instances );
// a_instances will be cleaned up automatically here. This also allows you some
// weak exception safety.
}
Remember that if even_more_values contains pointers to other objects, you will need to delete those objects in the destructor of a_class. If possible, even_more_values should contain the objects themselves rather than pointers to those objects (that way you may not have to write a destructor for a_class, the one the compiler provides for you may be sufficient).