I have a resource managed by an external system with the following API:
struct api {
resource* acquire();
void release(resource*);
};
My code requires to temporarily share one of these resources across multiple threads, so I need to put the resource in a shared_ptr to get a reference count:
std::shared_ptr<resource> res = m_api.acquire();
This API requires the resources being freed from the same thread in which they were acquired.
My problem is giving it back when all the threads are done with that resource, as std::shared_ptr does not have release.
1/ I cannot just let the pointers wither on their own when they aren't used as I don't know which thread will be the last if I do that (and it needs to be the main thread).
2/ I need to add a custom deleter which stores a api*, which is too costly in this case - I can already barely afford a "simple" std::shared_ptr with its default deleter.
What are my solutions, if possible without having to reimplement an atomic reference count myself ?
Related
I am running a thread pool where a function that is being called in the threads needs the mongocxx::pool pool variable so it can call pool.acquire() to get a client. I can't seem to pass the pool variable. How can I pass the pool variable. Or can I some how make pool global through out my application?
I am following this example https://github.com/mongodb/mongo-cxx-driver/blob/master/examples/mongocxx/pool.cpp
The mongocxx::pool class isn't copyable, so you can't pass it around (though you could std::move it around, though that probably is not useful for your case). If you want a shared instance, you need to keep it on the heap and provide a way for different parts of the code to access that shared resource, perhaps via shared_ptr. Have a look at the instance_management example in the sources for one example of how to manage a pool, via a singleton.
My API computes some data in its own thread:
/*** API is running in its own thread ***/
class API {
public:
std::shared_ptr<Data> retrieveData() { return mData; }
private:
std::shared_ptr<Data> mData;
std::mutex mDataMutex;
void run () {
std::thread t([](){
while (!exitApi) {
mDataMutex.lock();
updateData(mData);
mDataMutex.unlock();
});
t.join();
}
};
An application that uses my API will retrieve the shared data in another thread:
/*** Application is running in another thread ***/
class Application {
private:
Api mApi;
void run () {
std::thread t([](){
while (!exitApp) {
std::shared_ptr<Data> data = mApi.retrieveData();
/* API thread can update the data while the App is using it! */
useData(data);
});
t.join();
}
How can I design my API so that there are no pitfalls for the application-developer when retrieving the data? I can think of three options but do not like any of them:
Instead of sharing the pointer, the API will return a copy of all the data. However, the amount of data can get quite large and copying it should be avoided.
The API will lock the data when it hands it over to the application and the application needs to explicitly ask the API to unlock it again after performing all computations. Even if documented correctly this is very much prone to deadlocks.
When the API hands over the data to the application retrieveData will also return an already locked std::unique_lock. Once the application is done with using the data it has to unlock the unique_lock. This is potentially less prone to error but still not very obvious for the application developer.
Are there any better options to design the API (in modern C++11 and beyond) that is as developer-friendly as possible?
TL;DR: Use shared_ptr with a custom deleter that calls unlock.
It think the two main approaches are:
Returning an immutable data structure so it can be shared between threads. This is makes for a clean API, but (as already mentioned) copying could be expensive. Some approaches to reduce the need for copying would be:
Use a copy-on-write data structure so that only some portions of the data need to be copied each time. Depending on your data this may be not be
possible, or it will be too much work to refactor.
Make use of move-references where possible to reduce the cost of copying. This alone probably won't be enough, but depends on your actual data.
Using locks around a mutable data structure. As is pointed out, this requires the API user to perform extra actions that may not be obvious. But smart pointers can be used to lessen the burden on the consumers:
One way to make it easier is to return a custom smart pointer that
unlocks in its destructor: Unlock happens when the caller's scope closes, so there are no unlock calls for the caller to worry about. The API consumer would pass the pointer by reference to its methods. For example func(locking_ptr& ptr). A simple implementation can be found here: https://stackoverflow.com/a/15876719/1617480.
To be able to pass that locking smart pointer by copy instead of by reference, some sort of reference counting scheme needs to be in place. You'd probably want to use shared_ptr internal to the locking smart pointer to avoid rolling your own thread-safe reference counting. More simply pass a custom deleter to shared_ptr that unlocks and deletes (No need to write a smart pointer at all).
Another type of smart pointer would surround every dereference -> in locks. I don't think this is appropriate for this use case, since it looks the API consumer wants a consistent view of the results. Here's an example of such a pointer: https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Execute-Around_Pointer
Another approach would involve closures, for example adding
// inside class API
void do_locked(std::function<void(Data*)>fun) {
std::guard_lock<std::mutex> gu(mDataMutex);
fun(mData);
}
and you could invoke it with a lambda expression
//inside Application::run2
mApi.do_locked([=](Data *dat) { useData(dat); });
I'm running into a problem where I can't get rid of the last shared pointer and I kinda need it actually.
So what I have is a manager and some worker threads. The manager keeps a collection of shared pointers to different resources. A worker may ask the manager for a shared pointer to a resource. There will always be 1 or more workers with a shared pointer to the resource. My end goal is that when all workers are done with the resource, the resource is deleted. However, in this scheme, the manager always maintains a shared pointer to the resource so even when no workers are hanging on to the shared pointer, the resource won't get deleted b/c the ref count should always be at least 1 since the manager is hanging onto it. I need the manager to hang on to a shared pointer to the reference so that if any worker comes asking for a shared pointer, the manager will be able to provide it one.
edit: When the resource is created a worker already has it. So at its creation its ref count should be two (manager has it, and a single worker has it). When the ref count hits one (only the manager has it), I would like it to be deleted. If the resource had already been deleted and a worker comes looking for it, the resource shall be recreated.
edit2: some code:
SomeSharedPointer Manager::getResource(String unique_id)
{ // if unique id exists, return its mapped shared pointer, if unique id doesn't exist, create the resource, assign it a shared pointer, and stick it in the map
}
class Worker
{
SomeSharedPointer my_sp;
Worker()
{
String someUniqueId = "http://blah.com"
my_sp = Manager::getResource(someUniqueId);
// do some work on the resource
}
~Worker()
{
my_sp.reset(); // done with resource
}
}
Why is the manager holding a shared_ptr (strong reference) to the object if it doesn't need to retain control, only pass it on? Not seeing your code, it seems like having the manager hold a weak_ptr and then pass that on to the workers, who lock it into a shared_ptr on their end. That will allow the manager to pass on references without owning one of its own.
class Worker
{
SomeSharedPointer my_sp;
Worker()
{
String someUniqueId = "http://blah.com"
weak_ptr wp = Manager::getResource(someUniqueId);
my_sp = wp.lock();
// do some work on the resource
}
~Worker()
{
//my_sp.reset(); // handled automatically, as part of how shared pointers work
}
}
If a worker finishes and releases the resource, it will be destroyed and the manager will no longer be able to hand out references (which can be tested in getResource and reloaded). This doesn't seem quite optimal, but is part of your design, so it should work like that well.
Edit: You could also have getResource return a shared pointer, and have the manager hold the weak pointer, attempt to lock, do checking/reloading internally, and then return the shared pointer. As weak_ptrs can't be directly created, that may work somewhat better.
On the other hand, you could provide a function to compliment the one providing the workers with the pointer that releases it and does count checking in the manager.
Use a weak pointer in the manager and shared pointer in the workers, when a worker comes asking for the pointer create a shared pointer using the lock method.
as in boost::shared_ptr fptr = weakfoo.lock();
if shared pointer is empty, the pointer has either been released by the last worker or has not been created yet and needs creating
I would definitely avoid any solutions that involve looking at the ref count... only pain will ensue :)
I think the following is key:
I need the manager to hang on to a shared pointer to the reference so that if any worker comes asking for a shared pointer, the manager will be able to provide it one.
You need to decide at which point no more workers can come asking for the shared pointer. Once you know that's the case, the master can simply reset its instance of the shared pointer, thereby releasing the reference.
I have an object (Client * client) which starts multiple threads to handle various tasks (such as processing incoming data). The threads are started like this:
// Start the thread that will process incoming messages and stuff them into the appropriate queues.
mReceiveMessageThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)receiveRtpMessageFunction, this, 0, 0);
These threads all have references back to the initial object, like so:
// Thread initialization function for receiving RTP messages from a newly connected client.
static int WINAPI receiveRtpMessageFunction(LPVOID lpClient)
{
LOG_METHOD("receiveRtpMessageFunction");
Client * client = (Client *)lpClient;
while(client ->isConnected())
{
if(client ->receiveMessage() == ERROR)
{
Log::log("receiveRtpMessageFunction Failed to receive message");
}
}
return SUCCESS;
}
Periodically, the Client object gets deleted (for various good and sufficient reasons). But when that happens, the processing threads that still have references to the (now deleted) object throw exceptions of one sort or another when trying to access member functions on that object.
So I'm sure that there's a standard way to handle this situation, but I haven't been able to figure out a clean approach. I don't want to just terminate the thread, as that doesn't allow for cleaning up resources. I can't set a property on the object, as it's precisely properties on the object that become inaccessible.
Thoughts on the best way to handle this?
I would solve this problem by introducing a reference count to your object. The worker thread would hold a reference and so would the creator of the object. Instead of using delete, you decrement from the reference count and whoever drops the last reference is the one that actually calls delete.
You can use existing reference counting mechanisms (shared_ptr etc.), or you can roll your own with the Win32 APIs InterlockedIncrement() and InterlockedDecrement() or similar (maybe the reference count is a volatile DWORD starting out at 1...).
The only other thing that's missing is that when the main thread releases its reference, it should signal to the worker thread to drop its own reference. One way you can do this is by an event; you can rewrite the worker thread's loop as calls to WaitForMultipleObjects(), and when a certain event is signalled, you take that to mean that the worker thread should clean up and drop the reference.
You don't have much leeway because of the running threads.
No combination of shared_ptr + weak_ptr may save you... you may call a method on the object when it's valid and then order its destruction (using only shared_ptr would).
The only thing I can imagine is to first terminate the various processes and then destroy the object. This way you ensure that each process terminate gracefully, cleaning up its own mess if necessary (and it might need the object to do that).
This means that you cannot delete the object out of hand, since you must first resynchronize with those who use it, and that you need some event handling for the synchronization part (since you basically want to tell the threads to stop, and not wait indefinitely for them).
I leave the synchronization part to you, there are many alternatives (events, flags, etc...) and we don't have enough data.
You can deal with the actual cleanup from either the destructor itself or by overloading the various delete operations, whichever suits you.
You'll need to have some other state object the threads can check to verify that the "client" is still valid.
One option is to encapsulate your client reference inside some other object that remains persistent, and provide a reference to that object from your threads.
You could use the observer pattern with proxy objects for the client in the threads. The proxies act like smart pointers, forwarding access to the real client. When you create them, they register themselves with the client, so that it can invalidate them from its destructor. Once they're invalidated, they stop forwarding and just return errors.
This could be handled by passing a (boost) weak pointer to the threads.
I have a question about boost::shared_ptr<T>.
There are lots of thread.
using namespace boost;
class CResource
{
// xxxxxx
}
class CResourceBase
{
public:
void SetResource(shared_ptr<CResource> res)
{
m_Res = res;
}
shared_ptr<CResource> GetResource()
{
return m_Res;
}
private:
shared_ptr<CResource> m_Res;
}
CResourceBase base;
//----------------------------------------------
// Thread_A:
while (true)
{
//...
shared_ptr<CResource> nowResource = base.GetResource();
nowResource.doSomeThing();
//...
}
// Thread_B:
shared_ptr<CResource> nowResource;
base.SetResource(nowResource);
//...
Q1
If Thread_A do not care the nowResource is the newest, will this part of code have problem?
I mean when Thread_B do not SetResource() completely, Thread_A get a wrong smart point by GetResource()?
Q2
What does thread-safe mean?
If I do not care about whether the resource is newest, will the shared_ptr<CResource> nowResource crash the program when the nowResource is released or will the problem destroy the shared_ptr<CResource>?
boost::shared_ptr<> offers a certain level of thread safety. The reference count is manipulated in a thread safe manner (unless you configure boost to disable threading support).
So you can copy a shared_ptr around and the ref_count is maintained correctly. What you cannot do safely in multiple threads is modify the actual shared_ptr object instance itself from multiple threads (such as calling reset() on it from multiple threads). So your usage is not safe - you're modifying the actual shared_ptr instance in multiple threads - you'll need to have your own protection.
In my code, shared_ptr's are generally locals or parameters passed by value, so there's no issue. Getting them from one thread to another I generally use a thread-safe queue.
Of course none of this addresses the thread safety of accessing the object pointed to by the shared_ptr - that's also up to you.
From the boost documentation:
shared_ptr objects offer the same
level of thread safety as built-in
types. 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)
simultaneously by multiple threads
(even when these instances are copies,
and share the same reference count
underneath.)
Any other simultaneous accesses result in undefined behavior.
So your usage is not safe, since it uses simultaneous read and write of m_res. Example 3 in the boost documentation also illustrates this.
You should use a separate mutex that guards the access to m_res in SetResource/GetResource.
Well, tr1::shared_ptr (which is based on boost) documentation tells a different story, which implies that resource management is thread safe, whereas access to the resource is not.
"...
Thread Safety
C++0x-only features are: rvalue-ref/move support, allocator support, aliasing constructor, make_shared & allocate_shared. Additionally, the constructors taking auto_ptr parameters are deprecated in C++0x mode.
The Thread Safety section of the Boost shared_ptr documentation says "shared_ptr objects offer the same level of thread safety as built-in types." The implementation must ensure that concurrent updates to separate shared_ptr instances are correct even when those instances share a reference count e.g.
shared_ptr a(new A);
shared_ptr b(a);
// Thread 1 // Thread 2
a.reset(); b.reset();
The dynamically-allocated object must be destroyed by exactly one of the threads. Weak references make things even more interesting. The shared state used to implement shared_ptr must be transparent to the user and invariants must be preserved at all times. The key pieces of shared state are the strong and weak reference counts. Updates to these need to be atomic and visible to all threads to ensure correct cleanup of the managed resource (which is, after all, shared_ptr's job!) On multi-processor systems memory synchronisation may be needed so that reference-count updates and the destruction of the managed resource are race-free.
..."
see
http://gcc.gnu.org/onlinedocs/libstdc++/manual/memory.html#std.util.memory.shared_ptr
m_Res is not threadsafe ,because it simultaneous read/write,
you need boost::atomic_store/load function to protects it.
//--- Example 3 ---
// thread A
p = p3; // reads p3, writes p
// thread B
p3.reset(); // writes p3; undefined, simultaneous read/write
Add, your class has a Cyclic-references condition; the shared_ptr<CResource> m_Res can't be a member of CResourceBase. You can use weak_ptr instead.