As an example in pseudocode:
MultiThreadedWorker worker;
Foo()
{
const Vector position = CreatePosition();
worker.StartWorker(Position);
}
MultiThreadedWorker::StartWorker(const Vector& myPosition)
{
... Do a bunch of async work that keeps referencing myPosition ...
}
This seems to be working for now, but I don't understand why because it seems that myPosition would end up pointing to nothing long before StartWorker completed.
Assuming this isn't safe, is there any solution other than just passing around everything by value or ensuring it's all on the heap?
std::async copies const references
So yes, it is safe. For a discussion of why it does, see Why does std::async copy its const & arguments?
It is programmers responsibility to ensure that variable live long enough so that it is not destroyed before any access through pointers or references. This can be achieved through at least by one of the following:
Ensure the thread ends before destroying the variable. You can run .join() on the thread before leaving the scope.
Create object on the heap. Create it using make_shared and pass shared_ptr. This ensures the object lives until the last reference is destroyed.
Note that there is another problem with threads and shared objects. If one thread writes when another thread reads to the same object, then it is a data race which is Undefined Behavior. Thread synchronization mechanisms such as std::mutex can be used to avoid this.
Related
example:
std::shared_ptr<config const> ClassA::getConfig() {
folly::SharedMutex::ReadHolder rh(rwConfigLock_);
return config_;
}
The return is in the lock. However, does the shared pointer get copied over before the lock is released? I am afraid of a situation where the shared_pointers counter would get written to by different threads at the same time.
shared_ptr itself is thread safe by design. So the code is safe with respect to returning the shared_ptr instance.
More precisely: it is required to copy config_ to be thread safe. And even the lock is not dispensable.
Assuming that your lock prevents config_ from being modified while the function executes, the copy of config_ is done while the lock is held. This is essential because shared_ptr does not provide strong thread safety. The latter is required to safely read a shared pointer instance that could be modified asynchronously.
The problem behind the scenes is that after shared_ptr read the pointer of config_ and before it incremented the reference counter config_ might just being assigned with a new object. In this case the assignment operator decrements the reference counter, and if it returns to 0 (because no reference except for config_ points to the old object) it discards the old object. Unfortunately your thread has read the old object pointer and tries to increment the counter of the object that is currently destroyed. This is UB.
The lock together with the copy prevents from this scenario, because at the time the lock is released the reference counter of the object behind config_ is at least 2. One for your copy and one for config_ itself. So the object cannot be destroyed by an assignment to config_.
I have a function that creates a bunch of local variables, then passes their addresses to a function that runs in a separate thread - something like this:
void MyFunction()
{
MyClass a;
AnotherClass b;
...
FinalClass z;
CallFunctionInNewThread(&a,&b,&c,...,&z);
}
Of course, these variables are destroyed when the MyFunction goes out of scope (so the function in a thread is now pointing to garbage), so this setup doesn't work. What are my options here? If I allocate the variables on the heap with 'new', I will never get a chance to delete them. If I make them smart pointers or similar, I'd have to make the threaded function accept them as smart pointers, or their reference count will not be increased so they will still get destroyed immediately. It seems like they kind of want to be member variables of a wrapper class of MyFunction, but there are a few hundred lines and tens of these things and that would just be crazy messy. Are there any other choices?
Are there any other choices?
Simply copy (if trivial) or move/swap the data (if heavy to create) -- similar to transferring ownership from one thread to the other. Seems Thread A really does not need a reference from the description. Bonus: This removes concurrent access complexities from your program.
One little trick you can do is to pass a semaphore object into the thread function and then wait for that semaphore to be signaled. You do need to check that the thread was created successfully.
The new thread first makes local copies of the values (or references in the case of smart pointers), then signals the semaphore and carries on.
The calling thread can then continue and drop those objects off its stack without interfering with your new thread. It can even delete the semaphore object since it is no longer required by either thread.
It does mean that the calling thread has to wait until the thread is started and has copied its data, but that probably will be a short time. If you are going to the effort of spawning a thread to do any work at all, then this slight delay in the parent thread ought to be acceptable.
I'm new to threading in C++, and I'm trying to get a clear picture about how memory is shared/not shared between threads. I'm using std::thread with C++11.
From what I've read on other SO questions, stack memory is owned by only one thread and heap memory is shared between threads. So from what I think I understand about the stack vs. the heap, the following should be true:
#include <thread>
using namespace std;
class Obj {
public:
int x;
Obj(){x = 0;}
};
int main() {
Obj stackObj;
Obj *heapObj = new Obj();
thread t([&]{
stackObj.x++;
heapObj->x++;
});
t.join();
assert(heapObj->x == 1);
assert(stackObj.x == 0);
}
forgive me if I screwed up a bunch of stuff, lambda syntax is very new to me. But hopefully what I'm trying to do is coherent.
Would this perform as I expect? And if not, what am I misunderstanding?
Memory is memory. An object in C++ occupies some location in memory; that location may be on a stack or on the heap, or it may have been statically allocated. It doesn't matter where the object is located: any thread that has a reference or pointer to the object may access the object. If two threads have a reference or a pointer to the object, then both threads may access it.
In your program, you create a worker thread (by constructing a std::thread) that executes the lambda expression you provide it. Because you capture both stackObj and heapObj by reference (using the [&] capture default), that lambda has references to both of those objects.
Those objects are both located on the main thread's stack (note that heapObj is a pointer-type object that is located on the main thread's stack and points to a dynamically allocated object that is located on the heap). No copies of these objects are made; rather, your lambda expression has references to the objects. It modifies the stackObj directly and modifies the object pointed to by heapObj indirectly.
After the main thread joins with the worker thread, both heapObj->x and stackObj.x have a value of 1.
If you had used the value capture default ([=]), your lambda expression would have copied both stackObj and heapObj. The expression stackObj.x++ in the lambda expression would increment the copy, and the stackObj that you declare in main() would be left unchanged.
If you capture the heapObj by value, only the pointer itself is copied, so while a copy of the pointer is used, it still points to the same dynamically allocated object. The expression heapObj->x++ would dereference that pointer, yielding the Obj you created via new Obj(), and increment its value. You would then observe at the end of main() that heapObj->x has been incremented.
(Note that in order to modify an object captured by value, the lambda expression must be declared mutable.)
I agree with James McNellis that heapObj->x and stackObj.x will be 1.
Furthermore, this code only works because you join immediately after spawning the thread. If you started the thread and then did more work while it runs, an exception could unwind the stack and suddenly the new thread's stackObj is invalid. That is why sharing stack memory between threads is a bad idea even if it's technically possible.
I wonder, is it safe to implement like this? :
typedef shared_ptr<Foo> FooPtr;
FooPtr *gPtrToFooPtr // global variable
// init (before any thread has been created)
void init()
{
gPtrToFooPtr = new FooPtr(new Foo);
}
// thread A, B, C, ..., K
// Once thread Z execute read_and_drop(),
// no more call to read() from any thread.
// But it is possible even after read_and_drop() has returned,
// some thread is still in read() function.
void read()
{
FooPtr a = *gPtrToFooPtr;
// do useful things (read only)
}
// thread Z (executed once)
void read_and_drop()
{
FooPtr b = *gPtrToFooPtr;
// do useful things with a (read only)
b.reset();
}
We do not know which thread would do the actual realease.
Does boost's shared_ptr do the release safely under circumstance like this?
According to boost's document, thread safety of shared_ptr is:
A shared_ptr instance can be "read" (accessed using only const
operations) simultaneously by multiple threads. Different shared_ptr
instances can be "written to" (accessed using mutable operations such
as operator= or reset) simultaneosly by multiple threads.
As far as I am concerned, the code above does not violate any of thread safety criteria I mentioned above. And I believe the code should run fine. Does anyone tell me if I am right or wrong?
Thanks in advance.
Editted 2012-06-20 01:00 UTC+9
The pseudo code above works fine. The shared_ptr implementation guarantees to work correctly under circumstances where multiple thread is accessing instances of it (each thread MUST access its own instance of shared_ptr instantiated by using copy constructor).
Note that in the pseudo code above, you must delete gPtrToFooPtr to have the shared_ptr implementation finally release (drop the reference count by one) the object it owns(not proper expression since it is not an auto_ptr, but who cares ;) ). And in this case, you must be aware of the fact that it may cause SIGSEGV in multithreaded application.
How do you define 'safe' here? If you define it as 'I want to make sure that the object is destroyed exactly once', then YES, the release is safe. However, the problem is that the two threads share one smart pointer in your example. This is not safe at all. The reset() performed by one thread might not be visible to the other thread.
As stated by the documentation, smart pointers offer the same guarantees as built in types (i.e., pointers). Therefore, it is problematic to perform an unguarded write while an other thread might still be reading. It is undefined when that other reading thread will see writes of the other one. Therefore, while one thread calls reset() the pointer might NOT be reset in the other thread, since the shared_ptr instance itself is shared.
If you want some sort of thread safety, you have to use two shared pointer instances. Then, of course, resetting one of them WILL NOT release the object, since the other thread still has a reference to it. Usually this behaviour is intended.
However, I think the bigger problem is that you are misusing shared_ptrs. It is quite uncommon to use pointers of shared_ptrs and to allocate the shared_ptr on the heap (using new). If you do that, you have the problem you wanted to avoid using smart pointers again (you have to manage the lifetime of the shared_ptr now). Maybe check out some example code about smart pointers and their usage first.
For your own good, I will be honest.
Your code is doing many things and almost all are simply useless and absurd.
typedef shared_ptr<Foo> FooPtr;
FooPtr *gPtrToFooPtr // global variable
A raw pointer to a smart pointer, cancels the advantage of automatic resource management and does not solve any problem.
void read()
{
FooPtr a = *gPtrToFooPtr;
// do useful things (read only)
}
a is not used in any meaningful way.
{
FooPtr b = ...
b.reset();
}
b.reset() is useless here, b is about to be destroyed anyway. b has no purpose in this function.
I am afraid you have no idea what you are doing, what smart pointers are for, how to use shared_ptr, and how to do MT programming; so, you end up with this absurd pile of useless features to not solve the problem.
What about doing simple things simply:
Foo f;
// called before others functions
void init() {
// prepare f
}
// called in many threads {R1, R2, ... Rn} in parallel
void read()
{
// use f (read-only)
}
// called after all threads {R1, R2, ... Rn} have terminated
void read_and_drop()
{
// reset f
}
read_and_drop() must not be called before it can be guaranteed that other threads are not reading f.
To your edit:
Why not call reset() first on the global shared_ptr?
If you were the last one to access the object, fine it is deleted, then you delete the shared_ptr on the heap.
If some other thread still uses it, you reduce the ref count by one, and "disconnect" the global ptr from the (still existing) object that is pointed-to. You can then safely delete the shared_ptr on the heap without affecting any thread that might still use it.
Suppose you have an object which can be accesed by many threads. A critical section is used to protect the sensitive areas. But what about the destructor? Even if I enter a critical section as soon as I enter the destructor, once the destructor has been called, is the object already invalidated?
My train of thought: Say I enter the destructor, and I have to wait on the critical section because some other thread is still using it. Once he is done, I can finish destroying the object. Does this make sense?
In general, you should not destroy an object until you know that no other thread is using it. Period.
Consider this scenario, based on your 'train of thought':
Thread A: Get object X reference
Thread A: Lock object X
Thread B: Get object X reference
Thread B: Block on object X lock
Thread A: Unlock object X
Thread B: Lock object X; unlock object X; destroy object X
Now consider what happens if the timing is slightly different:
Thread A: Get object X reference
Thread B: Get object X reference
Thread B: Lock object X; unlock object X; destroy object X
Thread A: Lock object X - crash
In short, object destruction must be synchronized somewhere other than the object itself. One common option is to use reference counting. Thread A will take a lock on the object reference itself, preventing the reference from being removed and the object being destroyed, until it manages to increment the reference count (keeping the object alive). Then thread B merely clears the reference and decrements the reference count. You can't predict which thread will actually call the destructor, but it will be safe either way.
The reference counting model can be implemented easily by using boost::shared_ptr or std::shared_ptr; the destructor will not run unless all shared_ptrs in all threads have been destroyed (or made to point elsewhere), so at the moment of destruction you know that the only pointer to the object remaining is the this pointer of the destructor itself.
Note that when using shared_ptr, it's important to prevent the original object reference from changing until you can capture a copy of it. Eg:
std::shared_ptr<SomeObject> objref;
Mutex objlock;
void ok1() {
objlock.lock();
objref->dosomething(); // ok; reference is locked
objlock.unlock();
}
void ok2() {
std::shared_ptr<SomeObject> localref;
objlock.lock();
localref = objref;
objlock.unlock();
localref->dosomething(); // ok; local reference
}
void notok1() {
objref->dosomething(); // not ok; reference may be modified
}
void notok2() {
std::shared_ptr<SomeObject> localref = objref; // not ok; objref may be modified
localref->dosomething();
}
Note that simultaneous reads on a shared_ptr is safe, so you can choose to use a read-write lock if it makes sense for your application.
If a object is in use then you should make sure that the destructor of the object is not being called before the use of the object ends. If this is the behavior you have then its a potential problem and it really needs to be fixed.
You should make sure that if one thread is destroying your objects then another thread should not be calling functions on that object or the first thread should wait till second thread completes the function calling.
Yes, even destructors might need critical sections to protect updating some global data which is not related to the class itself.
It's possible that while one thread is waiting for CS in destructor the other is destroying the object and if CS belongs to object it will be destroyed as well. So that's not a good design.
You absolutely, positively need to make sure your object lifetime is less than the consumer threads, or you are in for some serious headaches. Either:
Make the consumers of the object children so it's impossible for them to exist outside of your object, or
use message passing/broker.
If you go the latter route, I highly recommend 0mq http://www.zeromq.org/.
Yes while you are in destructor, the object is already invalidated.
I used Destroy() method that enters critical section and then destroys it self.
Lifetime of object is over before destructor is called?
Yes, it is fine to do that. If a class supports such use, clients don't need to synchronize destruction; i.e. they don't need to make sure that all other methods on the object have finished before invoking the destructor.
I would recommend that clients not assume they can do this unless it is explicitly documented. Clients do have this burden, by default, with standard library objects in particular(§17.6.4.10/2).
There are cases where it is fine, though; std::condition_variable's destructor, for example, specifically allows ongoing condition_variable::wait() method invocations when ~condition_variable() starts. It only requires that clients not initiate calls to wait() after ~condition_variable() starts.
It might be cleaner to require that the client synchronize access to the destructor – and constructor for that matter – like most of the rest of the standard library does. I would recommend doing that if feasible.
However, there are certain patterns where it might make sense to relieve clients of the burden of fully synchronizing destruction. condition_variable's overall pattern seems like one: consider use of an object that handles possibly long-running requests. The user does the following:
Construct the object
Cause the object to receive requests from other threads.
Cause the object to stop receiving requests: at this point, some outstanding requests might be ongoing, but no new ones can be invoked.
Destroy the object. The destructor will block until all requests are done, otherwise the ongoing requests might have a bad time.
An alternative would be to require that clients do need to synchronize access. You could imagine step 3.5 above where the client calls a shutdown() method on the object that does the blocking, after which it is safe for the client to destroy the object. However, this design has some downsides; it complicates the API and introduces an additional state for the object of shutdown-but-valid.
Consider instead perhaps getting step (3) to block until all requests are done. There are tradeoffs...