[shared_ptr] Optimization suggestion

Hi All, For my own work in the thread-safe smart pointer arena, I have used a technique to reduce the number of mutex objects from one per object, yet minimize induced contention. The basic idea is a static pool of mutexes indexed by hashed pointers. Or in pseudo code: mutex & get_object_mutex (const void * p) // see below { const size_t pool_size = 127; static mutex pool[mutex_pool_size]; unsigned long ul = reinterpret_cast<unsigned long>(p); unsigned long hash = ...; // munge ul in some clever way return pool[ hash % pool_size ]; } class foo { public: void bar () { #ifdef BOOST_HAS_THREADS mutex::scoped_lock guard(get_object_mutex(this)); #endif // ... do something ... } }; This is a tad simplified. For example, I used my Singleton template to manage the pool, but the idea is the same. Instead of allocating one mutex per object that might need one, allocate a pool of them and hash the object's pointer so that all references to the same object use the same mutex. Has anyone considered using this technique in shared_count? The extra contention could be controlled by the sizeof the pool, and it would be a big savings where lots of objects are used. It would also be better than the lightweight_mutex used on some platforms (such as Windows) to achieve similar savings. At least that would be so if the mutex used where a CRITICAL_SECTION and not a kernel mutex. Best, Don ===== __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com

Don G wrote:
Hi All,
For my own work in the thread-safe smart pointer arena, I have used a technique to reduce the number of mutex objects from one per object, yet minimize induced contention. The basic idea is a static pool of mutexes indexed by hashed pointers. [...]
Has anyone considered using this technique in shared_count?
Yes, I had considered a mutex pool. One problem is that boost::shared_ptr is header-only, and must remain so for backward compatibility reasons. Another problem is that a CRITICAL_SECTION needs to be dynamically initialized before use, but the initialization itself also needs synchronization. It is easy to apply this optimization to std::tr1::shared_ptr, though, since standard libraries don't need to be header-only and can initialize things before everything else. ;-)

Hi Peter,
Yes, I had considered a mutex pool. One problem is that boost::shared_ptr is header-only, and must remain so for backward compatibility reasons.
Well, that would preclude such an optimization, though I am not sure how adding a .cpp file would break code (just makefiles<g>).
Another problem is that a CRITICAL_SECTION needs to be dynamically initialized before use, but the initialization itself also needs synchronization.
Unless it happens at global construction time as with Singleton. You are correct that the pseudo code I posted would not work if mutex == CRITICAL_SECTION.
It is easy to apply this optimization to std::tr1::shared_ptr, though, since standard libraries don't need to be header-only and can initialize things before everything else. ;-)
Good news indeed! Best, Don ===== __________________________________ Do you Yahoo!? Read only the mail you want - Yahoo! Mail SpamGuard. http://promotions.yahoo.com/new_mail

Don G <dongryphon@yahoo.com> writes:
Hi Peter,
Yes, I had considered a mutex pool. One problem is that boost::shared_ptr is header-only, and must remain so for backward compatibility reasons.
Well, that would preclude such an optimization, though I am not sure how adding a .cpp file would break code (just makefiles<g>).
You can almost always replace anything that "needs" to go in a .cpp file with a single template specialization. template <class Ignored = void> struct whatever_ { // ... static some_type thing; } typedef whatever_<> whatever; Now use whatever:: to access everything. Seems like it could work in this case. -- Dave Abrahams Boost Consulting www.boost-consulting.com
participants (3)
-
David Abrahams
-
Don G
-
Peter Dimov