Proposal for a thread "collision" detector
I would like to know if Boost community could be interested in adopting a check mechanism that is able to detect if a not supposed thread safe class is used by multiple threads in unsafe way. This tecnique has saved us a lot of headache especially when code refactoring on old code is performed. Better to explain it, without enter in the detail of the implementation, with some examples: Example: Queue implementation non thread-safe but still usable if clients are synchronized somehow. class NonThreadSafeQueue { public: ... void push(int) { DFAKE_SCOPED_LOCK(push_pop_); ... } int pop() { DFAKE_SCOPED_LOCK(push_pop_); ... } ... private: DFAKE_MUTEX(push_pop_); }; Example: Queue implementation not usable even if clients are synchronized, so only one thread in the class life cycle can use the two members push/pop. In this case the macro DFAKE_SCOPED_LOCK_THREAD_LOCKED pins the specified critical section the first time a thread enters push or pop, from that time on only that thread is allowed to execute push or pop. class NonThreadSafeQueue { public: ... void push(int) { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... } int pop() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... } ... private: DFAKE_MUTEX(push_pop_); }; Example: Class that has to be contructed/destroyed on same thread, it has a "shareable" method (with external syncronization) and a not shareable method (even with external synchronization). In this case 3 Critical sections have to be defined class ExoticClass { public: ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... } ~ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... } void Shareable() { DFAKE_SCOPED_LOCK(shareable_section_); ... } void NotShareable() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... } ... private: DFAKE_MUTEX(ctor_dtor_) DFAKE_MUTEX(shareable_section_) }; DFAKE_SCOPED_LOCK will "throw an exception" or will call an "abort" in case of check failed. This tecnique doesn't involve real lock/unlock but uses atomic operations, also the various macros DFAKE_XXXXXXXXX are defined void when NDEBUG is defined. Any comment is appreciated. Regards Gaetano Mendola
I'd be interested. Regards Hartmut --------------- http://boost-spirit.com http://stellar.cct.lsu.edu
-----Original Message----- From: Boost [mailto:boost-bounces@lists.boost.org] On Behalf Of Gaetano Mendola Sent: Friday, June 14, 2013 5:44 AM To: boost@lists.boost.org Subject: [boost] Proposal for a thread "collision" detector
I would like to know if Boost community could be interested in adopting a check mechanism that is able to detect if a not supposed thread safe class is used by multiple threads in unsafe way. This tecnique has saved us a lot of headache especially when code refactoring on old code is performed.
Better to explain it, without enter in the detail of the implementation, with some examples:
Example: Queue implementation non thread-safe but still usable if clients are synchronized somehow.
class NonThreadSafeQueue { public: ... void push(int) { DFAKE_SCOPED_LOCK(push_pop_); ... } int pop() { DFAKE_SCOPED_LOCK(push_pop_); ... } ... private: DFAKE_MUTEX(push_pop_); };
Example: Queue implementation not usable even if clients are synchronized, so only one thread in the class life cycle can use the two members push/pop.
In this case the macro DFAKE_SCOPED_LOCK_THREAD_LOCKED pins the specified critical section the first time a thread enters push or pop, from that time on only that thread is allowed to execute push or pop.
class NonThreadSafeQueue { public: ... void push(int) { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... } int pop() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... } ... private: DFAKE_MUTEX(push_pop_); };
Example: Class that has to be contructed/destroyed on same thread, it has a "shareable" method (with external syncronization) and a not shareable method (even with external synchronization).
In this case 3 Critical sections have to be defined
class ExoticClass { public: ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... } ~ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... }
void Shareable() { DFAKE_SCOPED_LOCK(shareable_section_); ... } void NotShareable() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... } ... private: DFAKE_MUTEX(ctor_dtor_) DFAKE_MUTEX(shareable_section_) };
DFAKE_SCOPED_LOCK will "throw an exception" or will call an "abort" in case of check failed.
This tecnique doesn't involve real lock/unlock but uses atomic operations, also the various macros DFAKE_XXXXXXXXX are defined void when NDEBUG is defined.
Any comment is appreciated.
Regards Gaetano Mendola
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
On 14.06.2013 14:43, Gaetano Mendola wrote:
I would like to know if Boost community could be interested in adopting a check mechanism that is able to detect if a not supposed thread safe class is used by multiple threads in unsafe way. This tecnique has saved us a lot of headache especially when code refactoring on old code is performed.
I used the same technique and it helped me a lot. I had a bit different interface though. 1. Mutex-like class that asserts that there is no two threads attempt to lock it simultaneously (similar to your DFAKE_SCOPED_LOCK lock type). Note, that it is convenient that this class is copyable so it can be used in copyable classes. 2. Class with the following interface: struct thread_affinity_checker : noncopyable { thread_affinity_checker(); ~thread_affinity_checker(); void check_current_thread() const; }; Its constructor remembers current thread-id. Destructor and check_current_thread() function asserts that id of current thread is the same as remembered in constructor. This class is useful if some class has thread affinity e.g. HWND (similar to your DFAKE_SCOPED_LOCK_THREAD_LOCKED). Generally I think that it's very useful to have DFAKE_SCOPED_LOCK in all appropriate classes in boost (containers especially). Possibly for small classes like smart-pointers, this check is costly, so it should be enabled only with special #define. Once it took me a lot of time to debug concurrent access to shared_ptr (assignment from it in one thread and assignment to it in another). If this technique existed back then it saved me a lot of time.
On 14/06/2013 12.43, Gaetano Mendola wrote:
I would like to know if Boost community could be interested in adopting a check mechanism that is able to detect if a not supposed thread safe class is used by multiple threads in unsafe way. This tecnique has saved us a lot of headache especially when code refactoring on old code is performed.
Better to explain it, without enter in the detail of the implementation, with some examples:
Example: Queue implementation non thread-safe but still usable if clients are synchronized somehow.
class NonThreadSafeQueue { public: ... void push(int) { DFAKE_SCOPED_LOCK(push_pop_); ... } int pop() { DFAKE_SCOPED_LOCK(push_pop_); ... } ... private: DFAKE_MUTEX(push_pop_); };
Example: Queue implementation not usable even if clients are synchronized, so only one thread in the class life cycle can use the two members push/pop.
In this case the macro DFAKE_SCOPED_LOCK_THREAD_LOCKED pins the specified critical section the first time a thread enters push or pop, from that time on only that thread is allowed to execute push or pop.
class NonThreadSafeQueue { public: ... void push(int) { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... } int pop() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... } ... private: DFAKE_MUTEX(push_pop_); };
Example: Class that has to be contructed/destroyed on same thread, it has a "shareable" method (with external syncronization) and a not shareable method (even with external synchronization).
In this case 3 Critical sections have to be defined
class ExoticClass { public: ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... } ~ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... }
void Shareable() { DFAKE_SCOPED_LOCK(shareable_section_); ... } void NotShareable() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... } ... private: DFAKE_MUTEX(ctor_dtor_) DFAKE_MUTEX(shareable_section_) };
DFAKE_SCOPED_LOCK will "throw an exception" or will call an "abort" in case of check failed.
This tecnique doesn't involve real lock/unlock but uses atomic operations, also the various macros DFAKE_XXXXXXXXX are defined void when NDEBUG is defined.
Any comment is appreciated.
To whom is interested in it, you can find in my blog http://cpp-today.blogspot.it/2008/06/threading-mess.html http://cpp-today.blogspot.it/2008/06/threading-mess-2.html an early implementation of the technique. My current implementation is different than that one in the blog in the sense that the macros have a different name (see my examples above) and it's using not GCC atomic operations but tbb::atomic. I don't know how to proceed (if) with the proposal for boost, for sure I have to modify my current implementation and write it in terms of boost::atomic (it uses tbb::atomic at the moment). I have also "donated" the code to google chromium project long time ago (I'm not even sure if they are still using it or not) and I don't know if that can be an issue for a boost adoption. Regards Gaetano Mendola
participants (3)
-
Gaetano Mendola
-
Hartmut Kaiser
-
Ivan Sorokin