Boost logo

Boost Users :

From: Aschwin Gopalan (yg-boost-users_at_[hidden])
Date: 2003-05-24 01:02:43


*****************************
Moderator's note:
Please trim excess quoting. It wastes bandwidth and makes it
difficult to find the important points among all the quoting.
*****************************

William E. Kempf wrote:

>
> Aschwin Gopalan said:
>> Dear Boosters!
>> I am designing a class template with policy controled threading
>> behaviour, like
>>
>> template<ThreadingModel=SingleThreaded>
>> class Something;
>>
>> where there are different ThreadingModels available (see Modern C++
>> Design by Alexandrescu for a discussion of policies).
>>
>> I would like to have Something to inherit ThreadingModel. The idea is
>> that SingleThreaded does not impose any additional penalties. So my Idea
>> was to have something like
>>
>> class SingleThreaded
>> {
>> public:
>> void lock() {}
>> void release() {}
>> }
>>
>> class MultiThreaded
>> {
>> public:
>> void lock() { lock_mutex(m_mutex) }
>> void release() { release_mutex(m_mutex) }
>> private:
>> mutex m_mutex;
>> }
>> and have all functions call lock() and release() accordingly.
>>
>> But this is not good, since it does not use Resource Initialization is
>> Aquisition and leads to exeption safety problems and so on. Furthermore,
>> it is not (because of these reasons) possible to model using
>> boost::mutex ?es since they do not expose a lock() release() interface
>> but can only be locked using scoped_locks.
>
> Sure it is, and this is what will be supplied in the next release. You
> have to create a "null_mutex" type (I need a better name) that has
> scoped_lock's that do nothing. This is similar to what you have below,
> but applied to a new mutex type instead of your policy base type.
>
>> So another idea is to have something like
>>
>> class SingleThreaded
>> {
>> class scoped_lock
>> {
>> // Empty class
>> }
>> }
>>
>> class MultiThreaded
>> {
>> public:
>> class scoped_lock
>> {
>> scoped_lock() // constructor that locks m_mutex of
>> // of MultiThreaded
>> ~scoped_lock() // unlocks
>> }
>> private:
>> boost::mutex m_mutex;
>> }
>>
>> and have the member functions lock the mutex by instantiating
>> an embeded scoped_lock object.
>>
>> Now there are some questions I have:
>> 1.) Does this approach sound sensible, or am I overlooking a commonly
>> used Idiom to achieve this functionality
>> 2.) How can I access the m_mutex member of the right object in
>> scoped_lock()? The only way I can imagin is to give the this
>> pointer to the constructor (like scoped_lock lock(this);). It is
>> somehow not nice, but possible
>
> Why is this "not nice"? The syntax is similar to current ScopedLock
> types.
>
>> 3.) The actual code I am using looks like
>>
>> //! Policy class.
>> /*! Multithreading, object operations are synchronized via
>> * a non-recursive lock, obeying strict Resource Acuisition is
>> Initialization
>> * semantics
>> */
>> class LockDefault
>> {
>> public:
>> LockDefault() :
>> m_pmutex(new boost::mutex)
>> {
>> }
>> class scoped_lock : public boost::mutex::scoped_lock
>> {
>> public:
>> scoped_lock(LockDefault &obj) :
>> boost::mutex::scoped_lock(obj->m_pmutex)
>> { }
>> ~scoped_lock() { }
>> };
>>
>> public:
>> boost::mutex m_mutex;
>>
>> };
>>
>> This works with gcc and I think it does what it should. It
>> fails to compile with VC++6 giving
>>
>> error C2512: 'scoped_lock<class boost::recursive_mutex>' : no
>> appropriate default constructor
>>
>> which I do not understand, since the default constructor is never
>> called.
>
> I can't explain it, mostly because the code you posted can't be what
> you're really using. You reference an m_pmutex when the only member is
> m_mutex and is not the pointer type the construction would indicate it
> should be.
You are obviosly right. See my followup for the correction. I copy-pasted it
out of the wrong policy class, wich I was just in progress to change to do
some more testing. Sorry about that.
>
>> Also, I do not like to have the mutex member public, but if I make it
>> private and write
>> friend class scoped_lock;
>> this does not have the desired effect (MSVC still complains about
>> private data member access)
>
> Not sure I have an answer here for the same reason.
>
>> Somehow, I must be getting something completely wrong, so
>> if somebody could point me in the right direction, I would be thankful.
>>
>> BTW: I am using boost_1_30_0
>
> I'm working on something similar for the next release. Here's a synopsis
> of the idea:
>
> class foo : public boost::syncrhonized<foo, boost::mutex>
> {
> public:
> void bar() { scoped_lock lock(this); bar(lock); }
> void bar(const scoped_lock& lock) {
> // do stuff
> }
> void baz() { scoped_lock lock(this); baz(lock); }
> void baz(const scoped_lock& lock) {
> // do stuff
> }
> };
>
> foo f;
> // Let the class do the synchronization
> f.bar();
> // Do the synchronization ourselves, for the right granularity
> { // Artificial block for lock
> foo::scoped_lock lock(f);
> f.bar(lock);
> f.baz(lock);
> } // Done with lock
>
> There's some implementation problems with this design that have to be
> worked out yet (for instance, we need a base class for ScopedLocks so that
> the above public methods for external synchronization don't have to be
> tied to specific lock types). I should have this implemented sometime
> this next week, though, so I'll keep you informed of progress.

This looks exactly like what I need, so I just will wait for your
implementation and stop bothering with my compiler problems :-)

BTW, is there something regarding thread termination in the works?
Actually, I am not sure if there is a safe way to do thread termination
without the thread cooperating. The problem I have is that if I use
blocking system calls (like read on blocking sockets) and the thread is
blocking on one of those, it cannot terminate itself. At the moment, I avoid
this by only using non-blocking sockets, but I would actually prefer to use
blocking sockets (its just easier to get right and nicer to read).

>
> BTW: This idea for external and internal locking is a variation on the
> Thread-Safe Interface design pattern suggested by Andrei Alexendrescu.

Where is it described? Is it in Moder C++ design?

Thanks for the swift response,

Aki
>


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net