[Boost.Smart_ptr] global_reset (revamp) for shared_ptr
Hello Boost-Users
CAVEAT
The attached code "works" but has a major design flaw
regarding pointer conversion safety -- one which can
currently either be accepted (at your risk) or
rectified by limiting usage to one-hop inheritance.
In particular, statement [3] (see below) is processed
without complaint in unsafe mode -- when it should
ideally provoke a compile-time error.
Indeed, providing a general type-safe solution is not
without challenge (read: my knowledge of C++ has been
exhausted). If interested, member function
'Common::reVamp' would be a good place to start.
PROBLEM
I recently needed a 'shared_ptr' that could be globally
reset -- that is, any one of the owners of the
controlled resource could unilaterally replace that
resource for the benefit (perhaps) of everyone else.
This has been named "global_reset" in previous postings
-- but I have adopted the shorter word "revamp".
Moreover, it would be useful if this newly conceived
"assign_ptr" could mimic the behavior of 'shared_ptr',
whilst simultaneously providing the additional
functionality. In particular, implicit upcasting
should be maintained.
This lead me to quickly reject options like:
shared_ptr
PROBLEM
I recently needed a 'shared_ptr' that could be globally reset -- that is, any one of the owners of the controlled resource could unilaterally replace that resource for the benefit (perhaps) of everyone else.
The replacement has to be able to deal with code that is in the process of using another smart pointer to the original object. I would solve this by having uses mark their in-use scope by simply fetching a local copy. That is, consider the explicit usage protocol: shared_ptr<mytype> global; to use: shared_ptr<mytype> local= global; // (A) local->foo(); // let local go out of scope to update: global= newvalue; // (B) Table a couple threading issues for the moment. I'd think of an approach that automated the "use" by having an operator-> that returned a shared_ptr. And, encapsulate the update step as a member function as well, so any needed locking or added steps can be accommodated. Back to the issues: I don't recall whether the shared_ptr documentation is clear as to whether multiple threads can issue (A) at the same time. Multiple threads executing (B) is not allowed. And whether (A) with one (B) can occur at the same time is probably related to multiple (A)'s, and certainly not specified in the standard. So, use a light-duty critical section of some kind to protect both of these. After getting that to work (portably), I'd see about eliminating the critical section around (A) if the implementation supports multiple (A)'s, by using a "swap" for B, and protecting against multiple calls to update. I've seen this pattern in the past. But we didn't use a special class to deal with it. Rather, the global thing was fetched with an accessor (so only a local smart pointer could be used by client code) and the update was only done internally to the library. TradeStation Group, Inc. is a publicly-traded holding company (NASDAQ GS: TRAD) of three operating subsidiaries, TradeStation Securities, Inc. (Member NYSE, FINRA, SIPC and NFA), TradeStation Technologies, Inc., a trading software and subscription company, and TradeStation Europe Limited, a United Kingdom, FSA-authorized introducing brokerage firm. None of these companies provides trading or investment advice, recommendations or endorsements of any kind. The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from any computer.
PROBLEM
I recently needed a 'shared_ptr' that could be globally reset -- that is, any one of the owners of the controlled resource could unilaterally replace that resource for the benefit (perhaps) of everyone else.
The replacement has to be able to deal with code that is in the
John Dlugosz wrote on Tuesday, August 18, 2009 2:47 PM: process of
using another smart pointer to the original object.
I would solve this by having uses mark their in-use scope by simply fetching a local copy.
That is, consider the explicit usage protocol:
shared_ptr<mytype> global;
to use: shared_ptr<mytype> local= global; // (A) local->foo(); // let local go out of scope
to update: global= newvalue; // (B)
Table a couple threading issues for the moment. I'd think of an approach that automated the "use" by having an operator-> that returned a shared_ptr. And, encapsulate the update step as a member function as well, so any needed locking or added steps can be accommodated.
Back to the issues: I don't recall whether the shared_ptr documentation is clear as to whether multiple threads can issue (A) at the same time. Multiple threads executing (B) is not allowed. And whether (A) with one (B) can occur at the same time is probably related to multiple (A)'s, and certainly not specified in the standard.
The threading issues are addressed at http://www.boost.org/doc/libs/1_39_0/libs/smart_ptr/shared_ptr.htm#Threa dSafety To summarize, there is no limit on the number of line A that can happen at any one time, but line B must have exclusive access to global. Ideally, you should have a reader-writer mutex to guard global. Lock it for read access (non-exclusive) for line A and unlock it before "local->foo()". Lock it for write access (exclusive) for line B. If you do not have a reader-writer mutex, then use an ordinary mutex to lock both line A and line B. This may, however hurt concurrency if line A is run frequently. Note that since I am not suggesting to use this mutex to lock "local->foo()", this in no way affects mytype's thread safety for good or ill.
Ideally, you should have a reader-writer mutex to guard global. Lock it for read access (non-exclusive) for line A and unlock it before "local->foo()". Lock it for write access (exclusive) for line B.
If you do not have a reader-writer mutex, then use an ordinary mutex to lock both line A and line B. This may, however hurt concurrency if line A is run frequently.
Since the critical section is so small, it may be more efficient to use the simplest light-duty construct possible to optimize for the case where there is no contention. That really depends on the usage in the final program, but I would expect from the description that accessing the pointer is a small part of what the program does. At the very least, it calls members via that pointer once it is obtained. On the other hand, having the atomic increment instruction inside the critical region will lengthen it from one or two instructions you expected to more like 40, as that stalls the pipeline. Some of my current work involves high-performance server code that even avoids these kinds of instructions. TradeStation Group, Inc. is a publicly-traded holding company (NASDAQ GS: TRAD) of three operating subsidiaries, TradeStation Securities, Inc. (Member NYSE, FINRA, SIPC and NFA), TradeStation Technologies, Inc., a trading software and subscription company, and TradeStation Europe Limited, a United Kingdom, FSA-authorized introducing brokerage firm. None of these companies provides trading or investment advice, recommendations or endorsements of any kind. The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from any computer.
participants (3)
-
Andrew Holden
-
John Dlugosz
-
Robbie Morrison