<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[multithreading: automatisches locking&#x2F;unlocking für variablen durch wrapperklasse]]></title><description><![CDATA[<p>hi,<br />
ich versuche eine klasseninstanz mit einem mutex zu verbinden und diesen dann automatisch zu locken, wenn eine memberfunktion der klasseninstanz aufgerufen wird.</p>
<p>hier mal etwas code:</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;string&gt;

namespace Private
{
    template&lt;class T, class TMutex&gt;
    struct Proxy
    {
        inline Proxy(TMutex&amp; m, T&amp; v):
        mMutex(m), mVariable(v) { mMutex.lock(); }

        inline ~Proxy() { mMutex.unlock(); }

        inline T* operator-&gt;() { return &amp;mVariable; }

        template&lt;class U&gt;
        inline void operator = (const U&amp; val) { mVariable = val; }

    private:
        T&amp;      mVariable;
        TMutex&amp; mMutex;
    };

    template&lt;class T, class TMutex&gt;
    struct Proxy&lt;const T,TMutex&gt;
    {
        inline Proxy(TMutex&amp; m, const T&amp; v):
        mMutex(m), mVariable(v) { mMutex.lock(); }

        inline ~Proxy() { mMutex.unlock(); }

        inline const T* operator-&gt;() const { return &amp;mVariable; }

        template&lt;class U&gt;
        inline void operator = (const U&amp; val) const { mVariable = val; }

    private:
        const T&amp; mVariable;
        TMutex&amp;  mMutex;
    };
}

template&lt;class T, class TMutex&gt;
class Protect
{
public:
    template&lt;class ...TArgs&gt;
    Protect(TMutex&amp; m, const TArgs&amp; ...args):
        mMutex(m), mVariable(args...) { }

    inline Private::Proxy&lt;T      ,TMutex&gt; operator-&gt;()       { return Private::Proxy&lt;T      ,TMutex&gt;(mMutex, mVariable); }
    inline Private::Proxy&lt;const T,TMutex&gt; operator-&gt;() const { return Private::Proxy&lt;const T,TMutex&gt;(mMutex, mVariable); }
    inline Private::Proxy&lt;T      ,TMutex&gt; operator *()       { return Private::Proxy&lt;T      ,TMutex&gt;(mMutex, mVariable); }
    inline Private::Proxy&lt;const T,TMutex&gt; operator *() const { return Private::Proxy&lt;const T,TMutex&gt;(mMutex, mVariable); }

private:
    T       mVariable;
    TMutex&amp; mMutex;
};

struct RecursiveMutexDummy
{
    RecursiveMutexDummy(): counter(0) { }
    void lock  () { std::cout &lt;&lt; &quot;lock &quot;   &lt;&lt; ++counter &lt;&lt; std::endl; }
    void unlock() { std::cout &lt;&lt; &quot;unlock &quot; &lt;&lt; counter-- &lt;&lt; std::endl; }
    int counter;
};

int main(int argc, char* args[])
{
    RecursiveMutexDummy m;
    Protect&lt;std::string,RecursiveMutexDummy&gt; safeString(m, &quot;hello&quot;);

    std::cout &lt;&lt; &quot;string: '&quot; &lt;&lt; safeString-&gt;c_str() &lt;&lt; &quot;' of size: &quot; &lt;&lt; safeString-&gt;length() &lt;&lt; std::endl;

    *safeString = &quot;world&quot;;

    std::cout &lt;&lt; &quot;string: '&quot; &lt;&lt; safeString-&gt;c_str() &lt;&lt; &quot;' of size: &quot; &lt;&lt; safeString-&gt;length() &lt;&lt; std::endl;
    return 0;
}
</code></pre>
<p>das funktioniert zwar soweit, trotzdem frage ich mich ob das so praktikabel ist (die performance mal außen vor gelassen).<br />
gibt es hier vielleicht irgendwelche schwerwiegenden seiteneffekte, die nicht so offensichtlich sind?</p>
<p>mfg<br />
plassy</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/253537/multithreading-automatisches-locking-unlocking-für-variablen-durch-wrapperklasse</link><generator>RSS for Node</generator><lastBuildDate>Sun, 13 Sep 2026 16:49:01 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/253537.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 03 Nov 2009 20:30:16 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to multithreading: automatisches locking&#x2F;unlocking für variablen durch wrapperklasse on Tue, 03 Nov 2009 20:30:16 GMT]]></title><description><![CDATA[<p>hi,<br />
ich versuche eine klasseninstanz mit einem mutex zu verbinden und diesen dann automatisch zu locken, wenn eine memberfunktion der klasseninstanz aufgerufen wird.</p>
<p>hier mal etwas code:</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;string&gt;

namespace Private
{
    template&lt;class T, class TMutex&gt;
    struct Proxy
    {
        inline Proxy(TMutex&amp; m, T&amp; v):
        mMutex(m), mVariable(v) { mMutex.lock(); }

        inline ~Proxy() { mMutex.unlock(); }

        inline T* operator-&gt;() { return &amp;mVariable; }

        template&lt;class U&gt;
        inline void operator = (const U&amp; val) { mVariable = val; }

    private:
        T&amp;      mVariable;
        TMutex&amp; mMutex;
    };

    template&lt;class T, class TMutex&gt;
    struct Proxy&lt;const T,TMutex&gt;
    {
        inline Proxy(TMutex&amp; m, const T&amp; v):
        mMutex(m), mVariable(v) { mMutex.lock(); }

        inline ~Proxy() { mMutex.unlock(); }

        inline const T* operator-&gt;() const { return &amp;mVariable; }

        template&lt;class U&gt;
        inline void operator = (const U&amp; val) const { mVariable = val; }

    private:
        const T&amp; mVariable;
        TMutex&amp;  mMutex;
    };
}

template&lt;class T, class TMutex&gt;
class Protect
{
public:
    template&lt;class ...TArgs&gt;
    Protect(TMutex&amp; m, const TArgs&amp; ...args):
        mMutex(m), mVariable(args...) { }

    inline Private::Proxy&lt;T      ,TMutex&gt; operator-&gt;()       { return Private::Proxy&lt;T      ,TMutex&gt;(mMutex, mVariable); }
    inline Private::Proxy&lt;const T,TMutex&gt; operator-&gt;() const { return Private::Proxy&lt;const T,TMutex&gt;(mMutex, mVariable); }
    inline Private::Proxy&lt;T      ,TMutex&gt; operator *()       { return Private::Proxy&lt;T      ,TMutex&gt;(mMutex, mVariable); }
    inline Private::Proxy&lt;const T,TMutex&gt; operator *() const { return Private::Proxy&lt;const T,TMutex&gt;(mMutex, mVariable); }

private:
    T       mVariable;
    TMutex&amp; mMutex;
};

struct RecursiveMutexDummy
{
    RecursiveMutexDummy(): counter(0) { }
    void lock  () { std::cout &lt;&lt; &quot;lock &quot;   &lt;&lt; ++counter &lt;&lt; std::endl; }
    void unlock() { std::cout &lt;&lt; &quot;unlock &quot; &lt;&lt; counter-- &lt;&lt; std::endl; }
    int counter;
};

int main(int argc, char* args[])
{
    RecursiveMutexDummy m;
    Protect&lt;std::string,RecursiveMutexDummy&gt; safeString(m, &quot;hello&quot;);

    std::cout &lt;&lt; &quot;string: '&quot; &lt;&lt; safeString-&gt;c_str() &lt;&lt; &quot;' of size: &quot; &lt;&lt; safeString-&gt;length() &lt;&lt; std::endl;

    *safeString = &quot;world&quot;;

    std::cout &lt;&lt; &quot;string: '&quot; &lt;&lt; safeString-&gt;c_str() &lt;&lt; &quot;' of size: &quot; &lt;&lt; safeString-&gt;length() &lt;&lt; std::endl;
    return 0;
}
</code></pre>
<p>das funktioniert zwar soweit, trotzdem frage ich mich ob das so praktikabel ist (die performance mal außen vor gelassen).<br />
gibt es hier vielleicht irgendwelche schwerwiegenden seiteneffekte, die nicht so offensichtlich sind?</p>
<p>mfg<br />
plassy</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1802883</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1802883</guid><dc:creator><![CDATA[Plassy]]></dc:creator><pubDate>Tue, 03 Nov 2009 20:30:16 GMT</pubDate></item><item><title><![CDATA[Reply to multithreading: automatisches locking&#x2F;unlocking für variablen durch wrapperklasse on Tue, 03 Nov 2009 20:44:01 GMT]]></title><description><![CDATA[<p>Plassy schrieb:</p>
<blockquote>
<p>hi,<br />
ich versuche eine klasseninstanz mit einem mutex zu verbinden und diesen dann automatisch zu locken, wenn eine memberfunktion der klasseninstanz aufgerufen wird.</p>
<p>...</p>
<p>gibt es hier vielleicht irgendwelche schwerwiegenden seiteneffekte, die nicht so offensichtlich sind?</p>
</blockquote>
<p>Deadlocks vlt?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1802892</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1802892</guid><dc:creator><![CDATA[OhneDenCodeZuLesen]]></dc:creator><pubDate>Tue, 03 Nov 2009 20:44:01 GMT</pubDate></item><item><title><![CDATA[Reply to multithreading: automatisches locking&#x2F;unlocking für variablen durch wrapperklasse on Tue, 03 Nov 2009 22:39:13 GMT]]></title><description><![CDATA[<p>Ohne den Code zu verstehen:<br />
<code>inline</code> ist dein lieblingswort, oder? Oo</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1802957</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1802957</guid><dc:creator><![CDATA[unskilled]]></dc:creator><pubDate>Tue, 03 Nov 2009 22:39:13 GMT</pubDate></item><item><title><![CDATA[Reply to multithreading: automatisches locking&#x2F;unlocking für variablen durch wrapperklasse on Wed, 04 Nov 2009 00:07:39 GMT]]></title><description><![CDATA[<blockquote>
<p>das funktioniert zwar soweit</p>
</blockquote>
<p>Nein, tut es nicht.</p>
<p>Nachdem dein Proxy kopierbar ist, und nicht korrekt damit umgeht wenn er kopiert/zugewiesen wird...:</p>
<pre><code class="language-cpp">template &lt;class T&gt;
void Kaboom(T t)
{
   T t1 = t;
   T t2 = t;
   T t3 = t;
}

int main(int argc, char* args[])
{
    RecursiveMutexDummy m;
    Protect&lt;std::string,RecursiveMutexDummy&gt; safeString(m, &quot;hello&quot;);

    Kaboom(*safeString);
}
</code></pre>
<p>Output:</p>
<pre><code>lock 1
unlock 1
unlock 0
unlock -1
unlock -2
unlock -3
</code></pre>
<p>Natürlich muss der Proxy zumindest &quot;movable&quot; sein, sonst kann man ihn ja nicht als Returntyp verwenden. Guck dir aber z.B. mal std::auto_ptr an, das ist ein &quot;gutes&quot; Beispiel dafür wie man Klassen auch ohne rvalue Referenzen &quot;movable&quot; machen kann.</p>
<p>Natürlich gibt es auch andere mögliche Lösungen.<br />
Und IMO sollte der Proxy auch &quot;gehalten&quot; werden können, also nicht unbedingt in einem &quot;privaten&quot; Namespace versteckt werden. Grund: wenn man mehrere Zugriffe auf das Objekt machen möchte, ist es vorteilhaft (und manchmal sogar nötig), den Lock über ein paar Statements hinweg zu halten.<br />
Natürlich gibt es in C++0x noch &quot;auto&quot; für solche Fälle, aber C++0x gibt's halt noch nicht (der von mir verwendete Template-Trick ist ja wirklich keine praktikable Lösung).</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1802973</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1802973</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Wed, 04 Nov 2009 00:07:39 GMT</pubDate></item><item><title><![CDATA[Reply to multithreading: automatisches locking&#x2F;unlocking für variablen durch wrapperklasse on Wed, 04 Nov 2009 15:11:04 GMT]]></title><description><![CDATA[<p>hustbaer schrieb:</p>
<blockquote>
<p>...</p>
</blockquote>
<p>danke für diese brauchbare antwort!<br />
du hast recht. das mit der kopierbarkeit des proxies habe ich nicht bedacht.<br />
allerding soll die proxy-klasse tatsächlich niemand zu gesicht bekommen.<br />
die Protect klasse soll nur die methoden aufrufe von mVariable schützen.</p>
<p>um den lock über mehrere anweisungen zu halten benutze ich eine andere wrapper klasse (ich möchte die funktionalität getrennt halten).</p>
<p>wenn ich den constructor und den copy-constructor des proxies private mache und<br />
die Protect klasse als friend deklariere sollte es eigendlich funktionieren.</p>
<p>ist es aber wirklich garantieret, dass der destructor des proxies aufgerufen wird sobald die anweisung beendet ist?<br />
oder kann es auch sein, dass der destructor erst am ende des blocks aufgerufen wird?<br />
bei letzterem szenario wäre ja die komplette idee hinfällig.</p>
<p>mfg<br />
plassy</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1803279</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1803279</guid><dc:creator><![CDATA[Plassy]]></dc:creator><pubDate>Wed, 04 Nov 2009 15:11:04 GMT</pubDate></item><item><title><![CDATA[Reply to multithreading: automatisches locking&#x2F;unlocking für variablen durch wrapperklasse on Wed, 04 Nov 2009 17:58:43 GMT]]></title><description><![CDATA[<p>Plassy schrieb:</p>
<blockquote>
<p>hustbaer schrieb:</p>
<blockquote>
<p>...</p>
</blockquote>
<p>um den lock über mehrere anweisungen zu halten benutze ich eine andere wrapper klasse (ich möchte die funktionalität getrennt halten).</p>
</blockquote>
<p>würde mich interessieren warum du das getrennt halten willst.</p>
<blockquote>
<p>wenn ich den constructor und den copy-constructor des proxies private mache und<br />
die Protect klasse als friend deklariere sollte es eigendlich funktionieren.</p>
</blockquote>
<p>scheint zu gehen. wundert mich jetzt etwas, aber ok. <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f615.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--confused_face"
      title=":confused:"
      alt="😕"
    /><br />
sogar comeau online frisst das.</p>
<p>ich glaube aber, dass das alleine nicht sicherstellt, dass der copy-ctor nicht aufgerufen wird. compiler die die RVO verwenden werden den copy-ctor nie aufrufen, aber ich würde mich nicht darauf verlassen. zumindest solltest du die entsprechende stelle im standard nachlesen, ob das wirklich garantiert ist.</p>
<blockquote>
<p>ist es aber wirklich garantieret, dass der destructor des proxies aufgerufen wird sobald die anweisung beendet ist?<br />
oder kann es auch sein, dass der destructor erst am ende des blocks aufgerufen wird?<br />
bei letzterem szenario wäre ja die komplette idee hinfällig.</p>
</blockquote>
<p>vereinfacht kann man IIRC sagen dass return werte (und andere rvalues/temporäre objekte) genau bis zum nächsten &quot;;&quot; leben.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1803388</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1803388</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Wed, 04 Nov 2009 17:58:43 GMT</pubDate></item><item><title><![CDATA[Reply to multithreading: automatisches locking&#x2F;unlocking für variablen durch wrapperklasse on Wed, 04 Nov 2009 19:57:28 GMT]]></title><description><![CDATA[<p>hustbaer schrieb:</p>
<blockquote>
<p>würde mich interessieren warum du das getrennt halten willst.</p>
</blockquote>
<p>also mein erstes beispiel war nur schnell zusammengecoded. ich wollte nur das wesentliche rüberbringen... naja...<br />
ich poste mal den code, so wie er aussehen soll um dir mein konzept zu verdeutlichen. der code sollte auch mit jedem compiler funktionieren (hoffe ich... ich bin schon voll in c++0x, sorry)<br />
die Guard klasse ist eigendlich nur ein wapper um einen mutex mit der man die eigendlichen &quot;lock guards&quot; erzeugt</p>
<p>ich hoffe, dass es nicht zu viel ist:</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;list&gt;

namespace Private
{
    template&lt;class T, class TGuard&gt;
    class Proxy
    {
        template&lt;class U, class V&gt; friend class SafeUsage;

        Proxy(TGuard&amp; m, T&amp; v):
            mGuard(m), mVariable(v) { mGuard.lock(); }

        Proxy(const Proxy&amp; p):
            mVariable(p.mVariable), mGuard(p.mGuard) { }

    public:
        ~Proxy() { mGuard.unlock(); }
        T* operator-&gt;() { return &amp;mVariable; }

        template&lt;class U&gt;
        void operator = (const U&amp; val) { mVariable = val; }

    private:
        T&amp;      mVariable;
        TGuard&amp; mGuard;
    };

    template&lt;class T, class TGuard&gt;
    class Proxy&lt;const T,TGuard&gt;
    {
        template&lt;class U, class V&gt; friend class SafeUsage;

        Proxy(TGuard&amp; m, const T&amp; v):
            mGuard(m), mVariable(v) { mGuard.lock(); }

        Proxy(const Proxy&amp; p):
            mVariable(p.mVariable), mGuard(p.mGuard) { }

    public:
        ~Proxy() { mGuard.unlock(); }
        const T* operator-&gt;() const { return &amp;mVariable; }

        template&lt;class U&gt;
        void operator = (const U&amp; val) const { mVariable = val; }

    private:
        const T&amp; mVariable;
        TGuard&amp;  mGuard;
    };
}

template&lt;class T, class TGuard&gt;
class SafeUsage
{
    template&lt;class U&gt;
    friend class Guard;

    SafeUsage(TGuard&amp; m, T&amp; v):
        mGuard(m), mVariable(v) { }

public:
    Private::Proxy&lt;T      ,TGuard&gt; operator-&gt;()       { return Private::Proxy&lt;T      ,TGuard&gt;(mGuard, mVariable); }
    Private::Proxy&lt;const T,TGuard&gt; operator-&gt;() const { return Private::Proxy&lt;const T,TGuard&gt;(mGuard, mVariable); }
    Private::Proxy&lt;T      ,TGuard&gt; operator *()       { return Private::Proxy&lt;T      ,TGuard&gt;(mGuard, mVariable); }
    Private::Proxy&lt;const T,TGuard&gt; operator *() const { return Private::Proxy&lt;const T,TGuard&gt;(mGuard, mVariable); }

private:
    T&amp;      mVariable;
    TGuard&amp; mGuard;
};

template&lt;class T, class TGuard&gt;
class SafeScope
{
    template&lt;class U&gt;
    friend class Guard;

    SafeScope(TGuard&amp; m, T&amp; v):
        mGuard(m), mVariable(v) { mGuard.lock(); }

public:
    ~SafeScope() { mGuard.unlock(); }

    T*       operator-&gt;()       { return &amp;mVariable; }
    const T* operator-&gt;() const { return &amp;mVariable; }
    T&amp;       operator* ()       { return mVariable;  }
    const T&amp; operator* () const { return mVariable;  }

private:
    TGuard&amp; mGuard;
    T&amp;      mVariable;
};

template&lt;class TMutex&gt;
class Guard // ich könnte eigendlich auch gleich von TMutex ableiten... however
{
public:
    void lock  () { mMutex.lock();   }
    void unlock() { mMutex.unlock(); }

    template&lt;class T&gt;
    SafeScope&lt;T,Guard&gt; protectInsideScope(T&amp; var) { return SafeScope&lt;T,Guard&gt;(*this, var); }

    template&lt;class T&gt;
    SafeUsage&lt;T,Guard&gt; protectUsageOf(T&amp; var) { return SafeUsage&lt;T,Guard&gt;(*this, var); }

private:
    TMutex mMutex;
};

struct RecursiveMutexDummy
{
    RecursiveMutexDummy(): counter(0) { }
    void lock  () { std::cout &lt;&lt; &quot;lock &quot;   &lt;&lt; ++counter &lt;&lt; std::endl; }
    void unlock() { std::cout &lt;&lt; &quot;unlock &quot; &lt;&lt; counter-- &lt;&lt; std::endl; }
    int counter;
}; 

int main()
{
    typedef Guard&lt;RecursiveMutexDummy&gt; Guardian;
    typedef std::list&lt;int&gt;             NumberList;

    Guardian   guardian;
    NumberList numbers;

    for(int i=0; i&lt;5; i++)
        numbers.push_back(i);

    // protect whole scope
    {
        SafeScope&lt;NumberList,Guardian&gt; guardedNumbers = guardian.protectInsideScope(numbers);

        for(NumberList::iterator i=guardedNumbers-&gt;begin(); i!=guardedNumbers-&gt;end(); i++)
            std::cout &lt;&lt; *i &lt;&lt; std::endl;
    }

    // protect only usage
    {
        SafeUsage&lt;NumberList,Guardian&gt; guardedNumbers = guardian.protectUsageOf(numbers);

        while(guardedNumbers-&gt;size())
        {
            std::cout &lt;&lt; guardedNumbers-&gt;front() &lt;&lt; std::endl;
            guardedNumbers-&gt;pop_front();
        }
    }

    return 0;
}
</code></pre>
<p>bin offen für anregungen <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f609.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--winking_face"
      title=";)"
      alt="😉"
    /></p>
<p>nochmal zu der copy-constructor sache:<br />
der code funktioniert so wie er jetzt ist mit dem g++ auch mit -O0 (keine optimierung).<br />
aber du hast recht, das könnte ein problem werden.<br />
hier müsste noch gekärt werden, wie die richtige vorgehensweise ist.</p>
<p>[edit] ahhh... ok, habs jetzt erst geschnallt <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f644.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--face_with_rolling_eyes"
      title=":rolling_eyes:"
      alt="🙄"
    />. ich könnte die Proxy und SafeScope klassen wie einen auto_ptr implementieren. dann würde immer die richtige anzahl an unlocks aufgrufen[/edit]</p>
<p>mfg<br />
plassy</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1803435</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1803435</guid><dc:creator><![CDATA[Plassy]]></dc:creator><pubDate>Wed, 04 Nov 2009 19:57:28 GMT</pubDate></item></channel></rss>