<?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[Mehrere std::mutex auf einmal so Ok?]]></title><description><![CDATA[<p>Hallo,</p>
<p>wenn ich eine Klasse (sagen wir hier mal <code>Test</code> ) habe, die von mehreren Threads benutzt werden soll. Dann kann ich ja deren Memberfunktionen mit Hilfe eines lock_guard entsprechen absichern und dadurch thread-safe machen:</p>
<pre><code>#include &lt;mutex&gt;

class Test
{
    mutable std::mutex mut, user_mut;
public:
    void foo()
    {
        std::lock_guard&lt;std::mutex&gt; lock(mut);
        // Do something thread safe
    }
    void bar()
    {
        std::lock_guard&lt;std::mutex&gt; lock(mut);
        // Do something else thread safe
    }
    std::mutex &amp;mutex() const
    {
        return user_mut;
    }
};

void do_something()
{
    Test test;
    test.foo();
    test.bar();
}
</code></pre>
<p>Die Funktionen <code>foo</code> und <code>bar</code> sind jetzt damit abgesichert und können von mehreren threads benutzt werden.</p>
<p>Das Objekt an sich aber nicht. Wenn ich jetzt mehrere Operationen hintereinander an test durchführen will, dann ist zwar jede einzelne für sich sicher, zwischen den Operationen könnten aber andere threads &quot;dazwischenfunken&quot;. Teilweise ist es aber (von der Logik her) notwendig, dass diese Funktionen alle seriell ausgeführt werden.</p>
<p>Deswegen hab ich mir überlegt noch einen zweiten Mutex einzuführen, oben mit <code>user_mut</code> bezeichnet. Dann könnte ein Benutzer folgendes machen um do_something abzusichern:</p>
<pre><code>void do_something()
{
    Test test;
    std::lock_guard&lt;std::mutex&gt; lock(test.mutex());

    test.foo();
    test.bar();
}
</code></pre>
<p>Jetzt die Frage: ist das so in Ordnung? Weil jetzt werden ja zwei verschiedene Mutex Objekte benutzt und auch gelockt, kann dadurch irgendwas fieses (Deadlock etc) passieren oder passt das so?</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/333358/mehrere-std-mutex-auf-einmal-so-ok</link><generator>RSS for Node</generator><lastBuildDate>Sun, 26 Apr 2026 22:37:50 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/333358.rss" rel="self" type="application/rss+xml"/><pubDate>Mon, 29 Jun 2015 08:46:57 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Mehrere std::mutex auf einmal so Ok? on Mon, 29 Jun 2015 08:46:57 GMT]]></title><description><![CDATA[<p>Hallo,</p>
<p>wenn ich eine Klasse (sagen wir hier mal <code>Test</code> ) habe, die von mehreren Threads benutzt werden soll. Dann kann ich ja deren Memberfunktionen mit Hilfe eines lock_guard entsprechen absichern und dadurch thread-safe machen:</p>
<pre><code>#include &lt;mutex&gt;

class Test
{
    mutable std::mutex mut, user_mut;
public:
    void foo()
    {
        std::lock_guard&lt;std::mutex&gt; lock(mut);
        // Do something thread safe
    }
    void bar()
    {
        std::lock_guard&lt;std::mutex&gt; lock(mut);
        // Do something else thread safe
    }
    std::mutex &amp;mutex() const
    {
        return user_mut;
    }
};

void do_something()
{
    Test test;
    test.foo();
    test.bar();
}
</code></pre>
<p>Die Funktionen <code>foo</code> und <code>bar</code> sind jetzt damit abgesichert und können von mehreren threads benutzt werden.</p>
<p>Das Objekt an sich aber nicht. Wenn ich jetzt mehrere Operationen hintereinander an test durchführen will, dann ist zwar jede einzelne für sich sicher, zwischen den Operationen könnten aber andere threads &quot;dazwischenfunken&quot;. Teilweise ist es aber (von der Logik her) notwendig, dass diese Funktionen alle seriell ausgeführt werden.</p>
<p>Deswegen hab ich mir überlegt noch einen zweiten Mutex einzuführen, oben mit <code>user_mut</code> bezeichnet. Dann könnte ein Benutzer folgendes machen um do_something abzusichern:</p>
<pre><code>void do_something()
{
    Test test;
    std::lock_guard&lt;std::mutex&gt; lock(test.mutex());

    test.foo();
    test.bar();
}
</code></pre>
<p>Jetzt die Frage: ist das so in Ordnung? Weil jetzt werden ja zwei verschiedene Mutex Objekte benutzt und auch gelockt, kann dadurch irgendwas fieses (Deadlock etc) passieren oder passt das so?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2458100</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2458100</guid><dc:creator><![CDATA[happystudent]]></dc:creator><pubDate>Mon, 29 Jun 2015 08:46:57 GMT</pubDate></item><item><title><![CDATA[Reply to Mehrere std::mutex auf einmal so Ok? on Mon, 29 Jun 2015 09:18:50 GMT]]></title><description><![CDATA[<p>Deadlock wohl nicht. Aber sicher ist das ja nur, wenn sich alle beteiligten daran halten, immer erst test.mutex zu locken.<br />
Wo ist dann aber noch der Sinn des internen Mutex?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2458105</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2458105</guid><dc:creator><![CDATA[Caligulaminus]]></dc:creator><pubDate>Mon, 29 Jun 2015 09:18:50 GMT</pubDate></item><item><title><![CDATA[Reply to Mehrere std::mutex auf einmal so Ok? on Mon, 29 Jun 2015 09:25:14 GMT]]></title><description><![CDATA[<p>Caligulaminus schrieb:</p>
<blockquote>
<p>Deadlock wohl nicht. Aber sicher ist das ja nur, wenn sich alle beteiligten daran halten, immer erst test.mutex zu locken.</p>
</blockquote>
<p>Ja, das ist ein Problem, allerdings ist mir bis jetzt keine Lösung dafür eingefallen...</p>
<p>Caligulaminus schrieb:</p>
<blockquote>
<p>Wo ist dann aber noch der Sinn des internen Mutex?</p>
</blockquote>
<p>Der Sinn ist, dass in 95% der Fälle nur eine Funktion an <code>test</code> aufgerufen wird. Dementsprechend nervig wäre es, jedesmal nochmal extra zu locken...</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2458107</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2458107</guid><dc:creator><![CDATA[happystudent]]></dc:creator><pubDate>Mon, 29 Jun 2015 09:25:14 GMT</pubDate></item><item><title><![CDATA[Reply to Mehrere std::mutex auf einmal so Ok? on Mon, 29 Jun 2015 09:42:38 GMT]]></title><description><![CDATA[<p>Nein, das ist nicht in Ordnung so. Wenn Du nicht konsistent denselben Mutex verwendest, kann es ja wieder zu Datenrennen kommen.</p>
<p>Du könntest denselben Mutex nutzen, dafür aber einen rekursiven und dann so etwas schreiben:</p>
<pre><code class="language-cpp">class Test
{
public:
    typedef std::recursive_mutex mtx_type;

    void foo()
    {
        std::lock_guard&lt;mtx_type&gt; lock(mut);
        // Do something thread safe
    }

    void bar()
    {
        std::lock_guard&lt;mtx_type&gt; lock(mut);
        // Do something else thread safe
    }

    std::unique_lock&lt;mtx_type&gt; lock() const
    {
        return std::unique_lock&lt;mtx_type&gt;(mut);
    }
private:
    mutable mtx_type mut;
};
</code></pre>
<pre><code class="language-cpp">void blah(Test&amp; obj)
{
    auto lck = obj.lock();
    obj.foo();
    obj.bar();
}
</code></pre>
<p>Alternativ könnte man das Locking-Zeugs komplett von Test trennen und dafür einen Wrapper benutzen, der einem nur über so ein lock-artiges Objekt den Zugriff auf das innere Objekt erlaubt, also</p>
<pre><code class="language-cpp">void blah(ThreadSafe&lt;Test&gt;&amp; obj)
{
    auto handle = obj.lock();
    handle-&gt;foo();
    handle-&gt;bar();
}
</code></pre>
<p>Das geht dann wieder ohne recursive_mutex und ist übrigens ziemlich genau der Ansatz, für den man sich in Rust entschieden hat, weil man so nicht vergessen kann, den Mutex zu &quot;locken&quot;.</p>
<p>Die Implementierung dieses Wrappers ist als Übung dem Leser überlassen. <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>
]]></description><link>https://www.c-plusplus.net/forum/post/2458110</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2458110</guid><dc:creator><![CDATA[krümelkacker]]></dc:creator><pubDate>Mon, 29 Jun 2015 09:42:38 GMT</pubDate></item><item><title><![CDATA[Reply to Mehrere std::mutex auf einmal so Ok? on Mon, 29 Jun 2015 09:35:21 GMT]]></title><description><![CDATA[<p>Oder</p>
<pre><code>void Test::foobar()
{
    std::lock_guard&lt;mtx_type&gt; lock(mut); // recursive_mutex
    foo();
    bar();
}
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2458112</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2458112</guid><dc:creator><![CDATA[Caligulaminus]]></dc:creator><pubDate>Mon, 29 Jun 2015 09:35:21 GMT</pubDate></item><item><title><![CDATA[Reply to Mehrere std::mutex auf einmal so Ok? on Mon, 29 Jun 2015 13:50:22 GMT]]></title><description><![CDATA[<p>Ok, ich hab jetzt auf <code>recursive_mutex</code> umgestellt, danke für die Hilfe <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f44d.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--thumbs_up"
      title=":+1:"
      alt="👍"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2458170</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2458170</guid><dc:creator><![CDATA[happystudent]]></dc:creator><pubDate>Mon, 29 Jun 2015 13:50:22 GMT</pubDate></item><item><title><![CDATA[Reply to Mehrere std::mutex auf einmal so Ok? on Mon, 29 Jun 2015 14:32:53 GMT]]></title><description><![CDATA[<p>Ich würde sagen es kommt drauf an ob man auf Performance optimiert oder nicht.<br />
Wenn nicht, dann kann man die Klasse einfach intern synchronisieren, und weiter nichts machen.<br />
Wenn der aufrufende Code dann mehrere Operationen ohne &quot;Unterbrechung&quot; auf den Objekten der Klasse durchführen möchte/muss, dann kann er extern nochmal synchronisieren. Also selbst eine eigene Mutex verwenden.</p>
<p>Wenn man auf Performance optimiert, dann kann man der Klasse einen Mutex-Getter verpassen, der Zugriff auf die &quot;innere&quot; Mutex gibt. (Bzw. so wie von krümelkacker gezeigt eine <code>lock()</code> Funktion die den fertig gelockten <code>unique_lock</code> zurückgibt.) Dann kann man noch für alle Methoden nicht lockende Alternativen machen, ala</p>
<pre><code class="language-cpp">class Test
{
public:

    void foo()
    {
        std::lock_guard&lt;mtx_type&gt; lock(mut);
        foo(lock);
    }

    void foo(std::lock_guard&lt;mtx_type&gt; const&amp; lock)
    {
        // Idealerweise prüft man hier dass lock wirklich gelockt ist und auch
        // wirklich die eigene Mutex gelockt hat (und nicht irgend eine andere)

        // do something
    }
//...
</code></pre>
<p>In dem Fall reicht dann auch ne normale Mutex, <code>recursive_mutex</code> ist nicht nötig.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2458176</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2458176</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Mon, 29 Jun 2015 14:32:53 GMT</pubDate></item></channel></rss>