How to protect functions from being called unsynchronized

Discussion in 'C++' started by Marcel Müller, May 24, 2010.

  1. I would like to protect some functions of a class from being called
    outside a synchronized context.

    Of course I could write a proxy that forwards all functions with an
    adjusted interface (see example below). But is is a bunch of work to
    forward all of these methods. Note that

    On the other hand I could use two interfaces one for synchronized class
    instances (maybe the class itself) and a second one for the thread-safe
    part. Unfortunately this causes a significant runtime overhead, since
    even trivial functions would require a vtable lookup while they would
    usually expanded inline else.

    Any other ideas?

    What a pity that one cannot define custom CV modifiers which would do
    the job. :)
    In fact I already abused volatile for strong thread safety. But this
    should have no drawback since the volatile Info instances cannot be
    accessed by ordinary statements anyway, since Info has no volatile methods.


    Marcel



    struct Info
    { Info() { }
    Info(const volatile Info& r)
    { // Strongly thread safe access
    }
    const char* GetString() const;
    // ...
    };

    class A
    { Info info;
    protected:
    void SyncMethod()
    { // ...
    }
    public:
    void OrdinaryMethod()
    { // ...
    }
    const volatile Info& GetInfo() const // strong thread safety required
    { return info; }

    public:
    class Sync;
    friend class Sync;
    class Sync
    { A& a;
    public:
    Sync(A& a) : a(a)
    { // Aquire mutex
    }
    ~Sync()
    { // Release mutex
    }
    public:
    void SyncMethod()
    { a.SyncMethod();
    }
    void OrdinaryMethod()
    { a.OrdinaryMethod();
    }
    const Info& GetInfo() const // remove strong thread safety tag
    { return const_cast<Info&>(a.GetInfo());
    }
    Info& GetInfo()
    { return a.info; }
    };
    };

    int main()
    {
    A a;
    a.OrdinaryMethod();
    //a.SyncMethod(); WRONG!
    Info i(a.GetInfo()); // strong thread safety required
    i.GetString(); // access Info content ...
    { // Hold mutex here
    A::Sync a_sync(a);
    a_sync.OrdinaryMethod();
    a_sync.SyncMethod(); // valid
    a_sync.GetInfo().GetString(); // no thread safety required
    }
    return 0;
    }
    Marcel Müller, May 24, 2010
    #1
    1. Advertising

  2. Marcel Müller

    Ian Collins Guest

    On 05/25/10 08:38 AM, Marcel Müller wrote:
    > I would like to protect some functions of a class from being called
    > outside a synchronized context.
    >
    > Of course I could write a proxy that forwards all functions with an
    > adjusted interface (see example below). But is is a bunch of work to
    > forward all of these methods. Note that


    It is also the most robust solution.

    > On the other hand I could use two interfaces one for synchronized class
    > instances (maybe the class itself) and a second one for the thread-safe
    > part. Unfortunately this causes a significant runtime overhead, since
    > even trivial functions would require a vtable lookup while they would
    > usually expanded inline else.


    Have you verified that? The above sounds like an attempt at premature
    optimisation.

    > Any other ideas?
    >
    > What a pity that one cannot define custom CV modifiers which would do
    > the job. :)
    > In fact I already abused volatile for strong thread safety. But this
    > should have no drawback since the volatile Info instances cannot be
    > accessed by ordinary statements anyway, since Info has no volatile methods.


    Eh? What is "strong thread safety"? Something is either thread safe or
    it isn't. The use of volatile does not imply thread safety.

    --
    Ian Collins
    Ian Collins, May 24, 2010
    #2
    1. Advertising

  3. Ian Collins wrote:
    > On 05/25/10 08:38 AM, Marcel Müller wrote:
    >> I would like to protect some functions of a class from being called
    >> outside a synchronized context.
    >>
    >> Of course I could write a proxy that forwards all functions with an
    >> adjusted interface (see example below). But is is a bunch of work to
    >> forward all of these methods. Note that

    >
    > It is also the most robust solution.


    For sure. But the question is with how much advance.

    >> On the other hand I could use two interfaces one for synchronized class
    >> instances (maybe the class itself) and a second one for the thread-safe
    >> part. Unfortunately this causes a significant runtime overhead, since
    >> even trivial functions would require a vtable lookup while they would
    >> usually expanded inline else.

    >
    > Have you verified that? The above sounds like an attempt at premature
    > optimisation.


    No I haven't verified that. But the calls, especially to GetInfo()
    happen really often. In some code regions approx. once per code line and
    inside a loop. (Calculation of recursive aggregate informations with
    cascading auto update if some properties change.)


    >> Any other ideas?
    >>
    >> What a pity that one cannot define custom CV modifiers which would do
    >> the job. :)
    >> In fact I already abused volatile for strong thread safety. But this
    >> should have no drawback since the volatile Info instances cannot be
    >> accessed by ordinary statements anyway, since Info has no volatile
    >> methods.

    >
    > Eh? What is "strong thread safety"? Something is either thread safe or
    > it isn't.


    Well, we had the same discussion in d.p.threads some time ago. In
    principal you are right, but in conjunction with reference counting you
    get an additional challenge. You cannot safely read a pointer from a
    public location and increment the reference counter where it points to
    lock free. In fact you have to protect any /reference/ to your reference
    counted object with it's own mutex, rather that only the reference
    counter - nearly impractical because of the exploding number of mutexes.
    The ability to safely get a reference to an existing object that you do
    /not/ currently own is called 'strong thread safety'.

    However, there are tricks around this with two or three implicitly
    atomic instructions per access. This is practical, but still not that
    cheap on multi core architectures, because of the memory barriers.


    > The use of volatile does not imply thread safety.


    I know. It is neither required nor sufficient.
    But if I define methods that use volatile instances in a thread safe
    way, then and only then it implies thread safety. This is a cheap trick
    to avoid to call the expensive thread-safe methods where they are not
    needed. In fact I utilize the otherwise mostly useless volatile modifier
    for this purpose, because otherwise I would need another proxy for every
    object which cannot be implemented in a generic way.


    Marcel
    Marcel Müller, May 24, 2010
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. George
    Replies:
    8
    Views:
    2,375
    Devdex Developer
    Sep 1, 2004
  2. Ahmed S. Badran

    Find the functions being called in a C file

    Ahmed S. Badran, May 31, 2004, in forum: C Programming
    Replies:
    4
    Views:
    524
    Ed Morton
    May 31, 2004
  3. Replies:
    0
    Views:
    268
  4. Hooyoo
    Replies:
    9
    Views:
    495
    Hooyoo
    Aug 28, 2007
  5. Felix
    Replies:
    1
    Views:
    328
    Felix
    Sep 29, 2006
Loading...

Share This Page