<?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[Code review von synchronized queue]]></title><description><![CDATA[<p>Ich bastle an einer synchronized queue. Der Code ist hier <a href="http://ideone.com/17IYk6" rel="nofollow">http://ideone.com/17IYk6</a> .</p>
<pre><code>#ifndef SYNC_H
#define SYNC_H

#include &lt;basic/queue.h&gt;
#include &lt;boost/thread.hpp&gt;

namespace af {
namespace sync {

template&lt;typename T&gt;
struct queue
{
    // for convenient
    typedef typename af::basic::queue&lt;T&gt; container;

    struct monitor_t
    {
        monitor_t() : q_(0) {};
        monitor_t(monitor_t&amp; m) : q_(m.q_) {}
        ~monitor_t() {}

        template&lt;typename F&gt;
        void operator()(F&amp; f) const
        {
            boost::lock_guard&lt;boost::mutex&gt; lock(q_-&gt;m_);
            q_-&gt;c_.notify_one();
            f(q_-&gt;q_);
        }

    private:
        queue* q_;
        // for setting reference
        friend monitor_t queue::monitor();

    };

    queue() : q_() {}

    bool empty() const
    {
        boost::lock_guard&lt;boost::mutex&gt; lock(m_);
        return q_.empty();
    }

    size_t size() const
    {
        boost::lock_guard&lt;boost::mutex&gt; lock(m_);
        return q_.size();
    }

    bool pop(T&amp; msg, unsigned int ms)
    {
        boost::system_time const timeout
            = boost::get_system_time()
            + boost::posix_time::milliseconds(ms);
        boost::unique_lock&lt;boost::mutex&gt; lock(m_);
        while( q_.empty())
        {
            if (!c_.timed_wait(lock, timeout))
                return false;
        }

        q_.pop(msg);
        return true;
    }

    // consumes msg and moves it into the queue
    void push(T&amp; msg)
    {
        boost::lock_guard&lt;boost::mutex&gt; lock(m_);
        q_.push(msg);
        c_.notify_one();
    }

    void clear()
    {
        boost::lock_guard&lt;boost::mutex&gt; lock(m_);
        q_.clear();
    }

    monitor_t monitor()
    {
        monitor_t tmp;
        tmp.q_ = this;
        return tmp;
    }

    ~queue()
    {
        clear();
    }

private:

    // do not copy
    queue(queue const&amp;);
    queue&amp; operator=(queue const&amp;);

    af::basic::queue&lt;T&gt; q_;
    mutable boost::mutex m_;
    boost::condition_variable c_;
};

}
}
</code></pre>
<p>Bei der Implementierung folge ich dem Beispiel aus <a href="http://www.youtube.com/playlist?list=PL1835A90FC78FF8BE" rel="nofollow">http://www.youtube.com/playlist?list=PL1835A90FC78FF8BE</a> . Aber da ich ab und an mehr als nur pop und push einzeln aufrufen moechte sondern als &quot;Transaktion&quot;, kann ich bei Bedarf ein Monitorobjekt benutzen. Dabei folge ich dem Beispiel monitor&lt;T&gt; aus <a href="http://isocpp.org/blog/2013/01/c-concurrency-herb-sutter" rel="nofollow">http://isocpp.org/blog/2013/01/c-concurrency-herb-sutter</a> (sollte in die Playlist) angepasst auf meine Queue.</p>
<p>Nun zu meinem Anliegen: Gibt es etwas zu verbessern oder zu aendern, sind Fehler enthalten? Fuer Kommentare bin ich dankbar. Das public Interface von af::basic::queue weicht von std::queue etwas ab und sieht folgendermassen aus:</p>
<pre><code class="language-cpp">template&lt;typename T&gt;
struct queue
{
    queue();
    bool empty() const;
    size_t size() const;
    void pop(T&amp; msg);
    void push(T&amp; msg);
    void clear();
    ~queue();
};
</code></pre>
<p>Es kompiliert gcc 4.72 und einfache Tests sind erfolgreich. Ich kann kein C++11 benutzen und bei boost bin ich auf Version 1.49.0 beschraenkt. Danke.</p>
<p>edit: code von ideone hierhergetragen.</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/313350/code-review-von-synchronized-queue</link><generator>RSS for Node</generator><lastBuildDate>Sun, 02 Aug 2026 03:55:15 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/313350.rss" rel="self" type="application/rss+xml"/><pubDate>Mon, 28 Jan 2013 16:33:49 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Code review von synchronized queue on Tue, 29 Jan 2013 13:11:10 GMT]]></title><description><![CDATA[<p>Ich bastle an einer synchronized queue. Der Code ist hier <a href="http://ideone.com/17IYk6" rel="nofollow">http://ideone.com/17IYk6</a> .</p>
<pre><code>#ifndef SYNC_H
#define SYNC_H

#include &lt;basic/queue.h&gt;
#include &lt;boost/thread.hpp&gt;

namespace af {
namespace sync {

template&lt;typename T&gt;
struct queue
{
    // for convenient
    typedef typename af::basic::queue&lt;T&gt; container;

    struct monitor_t
    {
        monitor_t() : q_(0) {};
        monitor_t(monitor_t&amp; m) : q_(m.q_) {}
        ~monitor_t() {}

        template&lt;typename F&gt;
        void operator()(F&amp; f) const
        {
            boost::lock_guard&lt;boost::mutex&gt; lock(q_-&gt;m_);
            q_-&gt;c_.notify_one();
            f(q_-&gt;q_);
        }

    private:
        queue* q_;
        // for setting reference
        friend monitor_t queue::monitor();

    };

    queue() : q_() {}

    bool empty() const
    {
        boost::lock_guard&lt;boost::mutex&gt; lock(m_);
        return q_.empty();
    }

    size_t size() const
    {
        boost::lock_guard&lt;boost::mutex&gt; lock(m_);
        return q_.size();
    }

    bool pop(T&amp; msg, unsigned int ms)
    {
        boost::system_time const timeout
            = boost::get_system_time()
            + boost::posix_time::milliseconds(ms);
        boost::unique_lock&lt;boost::mutex&gt; lock(m_);
        while( q_.empty())
        {
            if (!c_.timed_wait(lock, timeout))
                return false;
        }

        q_.pop(msg);
        return true;
    }

    // consumes msg and moves it into the queue
    void push(T&amp; msg)
    {
        boost::lock_guard&lt;boost::mutex&gt; lock(m_);
        q_.push(msg);
        c_.notify_one();
    }

    void clear()
    {
        boost::lock_guard&lt;boost::mutex&gt; lock(m_);
        q_.clear();
    }

    monitor_t monitor()
    {
        monitor_t tmp;
        tmp.q_ = this;
        return tmp;
    }

    ~queue()
    {
        clear();
    }

private:

    // do not copy
    queue(queue const&amp;);
    queue&amp; operator=(queue const&amp;);

    af::basic::queue&lt;T&gt; q_;
    mutable boost::mutex m_;
    boost::condition_variable c_;
};

}
}
</code></pre>
<p>Bei der Implementierung folge ich dem Beispiel aus <a href="http://www.youtube.com/playlist?list=PL1835A90FC78FF8BE" rel="nofollow">http://www.youtube.com/playlist?list=PL1835A90FC78FF8BE</a> . Aber da ich ab und an mehr als nur pop und push einzeln aufrufen moechte sondern als &quot;Transaktion&quot;, kann ich bei Bedarf ein Monitorobjekt benutzen. Dabei folge ich dem Beispiel monitor&lt;T&gt; aus <a href="http://isocpp.org/blog/2013/01/c-concurrency-herb-sutter" rel="nofollow">http://isocpp.org/blog/2013/01/c-concurrency-herb-sutter</a> (sollte in die Playlist) angepasst auf meine Queue.</p>
<p>Nun zu meinem Anliegen: Gibt es etwas zu verbessern oder zu aendern, sind Fehler enthalten? Fuer Kommentare bin ich dankbar. Das public Interface von af::basic::queue weicht von std::queue etwas ab und sieht folgendermassen aus:</p>
<pre><code class="language-cpp">template&lt;typename T&gt;
struct queue
{
    queue();
    bool empty() const;
    size_t size() const;
    void pop(T&amp; msg);
    void push(T&amp; msg);
    void clear();
    ~queue();
};
</code></pre>
<p>Es kompiliert gcc 4.72 und einfache Tests sind erfolgreich. Ich kann kein C++11 benutzen und bei boost bin ich auf Version 1.49.0 beschraenkt. Danke.</p>
<p>edit: code von ideone hierhergetragen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2294182</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2294182</guid><dc:creator><![CDATA[knivil]]></dc:creator><pubDate>Tue, 29 Jan 2013 13:11:10 GMT</pubDate></item><item><title><![CDATA[Reply to Code review von synchronized queue on Mon, 28 Jan 2013 16:47:09 GMT]]></title><link>https://www.c-plusplus.net/forum/post/2294187</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2294187</guid><dc:creator><![CDATA[cooky451]]></dc:creator><pubDate>Mon, 28 Jan 2013 16:47:09 GMT</pubDate></item><item><title><![CDATA[Reply to Code review von synchronized queue on Mon, 28 Jan 2013 17:16:08 GMT]]></title><description><![CDATA[<p>Warum unique_lock in pop() ?</p>
<p>Ansonsten ist mir das notify_one in monitor nicht ganz geheuer. Aber das ist nur ein Gefühl ohne dass ich es belegen kann. Ich habe das Video von Herb Sutter dazu jetzt aber auch nicht gesehen.</p>
<p>Eine Optimierungsmöglichkeit wären 2 Arten von Locks: read und write. size() und empty() brauchen nur readlocks während pop und push write Locks brauchen. Ob das eine optimierung ist, weiß ich aber nicht. Es wäre aber auf jedenfall eine Option die man sich anschauen könnte.</p>
<p>uU wäre ein non blocking pop auch interessant. Also eins ohne timed_wait. Wobei man das wahrscheinlich mit einem 0 als Parameter simulieren könnte. Gefühlt könnte man hier aber mit einem eigenen empty test in pop etwas rausholen.</p>
<p>Sieht aber eigentlich alles OK aus.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2294199</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2294199</guid><dc:creator><![CDATA[Shade Of Mine]]></dc:creator><pubDate>Mon, 28 Jan 2013 17:16:08 GMT</pubDate></item><item><title><![CDATA[Reply to Code review von synchronized queue on Mon, 28 Jan 2013 20:04:20 GMT]]></title><description><![CDATA[<p>Ich mag keine absoluten Timeouts. Ist zwar (viel) einfacher &quot;korrekt&quot; zum implementieren als mit relativen (vor allem weil die Standard-Library keine &quot;timeout clock&quot; Klasse zur Verfügung stellt -- oder gibt es sowas?), aber dafür ist es eben auch nur &quot;korrekt&quot; und nicht korrekt: bei Änderungen der Systemzeit kann es zu Problemen kommen.</p>
<p>~~<br />
Und die Monitor-Sache könnte problematisch werden, wenn die &quot;gemonitorte&quot; Funktion [c]pop[/c] aufruft. Dann wäre die Mutex nämlich doppelt gelockt, und könnte daher durch das [c]timed_lock[/c] nicht mehr entsperrt werden.</p>
<p>Eine Möglichkeit das zu lösen wäre z.B. direkten Zugriff auf die Mutex zu geben, und einen pop-Overload zu machen der ein [c]unique_lock[/c] Objekt als Parameter nimmt.<br />
Oder die Queue selbst lockbar machen, so dass man ein [c]unique_lock&lt;my_queue&gt;[/c] verwenden kann.<br />
Oder dem Funktor den der Monitor ausführt als Parameter das [c]unique_lock[/c] mitgeben - irgendsowas.~~<br />
EDIT: ich sehe gerade du übergibst ja direkt ne Referenz auf die interne &quot;nicht threadsafe&quot; queue an die Funktion. Dadurch gibt es das von mir oben beschriebene Problem natürlich nicht mehr.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2294284</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2294284</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Mon, 28 Jan 2013 20:04:20 GMT</pubDate></item><item><title><![CDATA[Reply to Code review von synchronized queue on Mon, 28 Jan 2013 20:02:22 GMT]]></title><description><![CDATA[<p>Shade Of Mine schrieb:</p>
<blockquote>
<p>Warum unique_lock in pop() ?</p>
</blockquote>
<p>Vermutlich weil man einen <code>lock_guard</code> nicht &quot;entlocken&quot; kann (oder geht das?) -- siehe <code>timed_lock</code> Aufruf.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2294285</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2294285</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Mon, 28 Jan 2013 20:02:22 GMT</pubDate></item><item><title><![CDATA[Reply to Code review von synchronized queue on Mon, 28 Jan 2013 20:07:15 GMT]]></title><description><![CDATA[<p>Shade Of Mine schrieb:</p>
<blockquote>
<p>Ansonsten ist mir das notify_one in monitor nicht ganz geheuer.</p>
</blockquote>
<p>Ja, da müsste wohl ein <code>notify_all</code> hin.<br />
Denn die aufgerufene Funktion kann ja mehr als einen Eintrag einfügen. Es würde dann aber nur einer der &quot;popper&quot; aufgeweckt, und das ist vermutlich nicht im Sinne des Erfinders.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2294287</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2294287</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Mon, 28 Jan 2013 20:07:15 GMT</pubDate></item><item><title><![CDATA[Reply to Code review von synchronized queue on Tue, 29 Jan 2013 09:21:46 GMT]]></title><description><![CDATA[<blockquote>
<p>Ich habe das Video von Herb Sutter dazu jetzt aber auch nicht gesehen.</p>
</blockquote>
<p>Kommt auch so nicht vor, da es im Video sehr einfach gehalten wurde.</p>
<p>hustbaer schrieb:</p>
<blockquote>
<p>Ja, da müsste wohl ein <code>notify_all</code> hin.<br />
Denn die aufgerufene Funktion kann ja mehr als einen Eintrag einfügen. Es würde dann aber nur einer der &quot;popper&quot; aufgeweckt, und das ist vermutlich nicht im Sinne des Erfinders.</p>
</blockquote>
<p>Korrekt, das wird im Monitor geaendert. Wie sieht das bei push aus, wenn 2 Elemente mittels push ohne Kontextwechsel eingefuegt werden und zwei Konsumer warten. Wird dann auch nur einer aufgeweckt? Ich glaube da muss ich nochmal im Standard zu pthread und boost nachlesen.</p>
<blockquote>
<p>wäre ein non blocking pop auch interessant. Also eins ohne timed_wait.</p>
</blockquote>
<p>Ja, darueber habe ich auch nachgedacht. Wollte das Interface mit <code>try_pop</code> (non blocking) und <code>pop</code> (blockierend ohne timeout) nicht ueberladen.</p>
<blockquote>
<p>Ich mag keine absoluten Timeouts.</p>
</blockquote>
<p>Ich auch nicht. Aber das C++11 Threadinterface mit <code>wait_for</code> steht mir leider nicht zur Verfuegung. Somit wird das relative Timeout am Interface in ein absolutes gewandelt. Der Benutzer der Klasse sieht nur das relative. Und ja, Systemzeit aendern ist fatal.</p>
<blockquote>
<p>Warum unique_lock in pop() ?</p>
</blockquote>
<p>Das Interface von <code>boost::condition_variable</code> aber auch von C++11s <code>std::condition_variable</code> sieht es vor. Und ja, <code>lock_guard</code> hat nur Konstruktor und Destruktor, kann also nicht unlocken.</p>
<blockquote>
<p>Eine Optimierungsmöglichkeit wären 2 Arten von Locks: read und write. size() und empty() brauchen nur readlocks während pop und push write Locks brauchen.</p>
</blockquote>
<p>Darueber werde ich nachdenken.</p>
<blockquote>
<p>Dann wäre die Mutex nämlich doppelt gelockt,</p>
</blockquote>
<p>Ja, ich haette ein Beispiel fuer die Benutzung angeben sollen. Die Funktion/Funktor bekommt ein <code>af::sync::queue&lt;T&gt;::container</code> (also hier <code>af::basic::queue&lt;T&gt;</code> ) und nicht <code>af::sync::queue&lt;T&gt;</code> .</p>
<p>Auf alle Faelle: Ich danke euch!</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2294390</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2294390</guid><dc:creator><![CDATA[knivil]]></dc:creator><pubDate>Tue, 29 Jan 2013 09:21:46 GMT</pubDate></item><item><title><![CDATA[Reply to Code review von synchronized queue on Tue, 29 Jan 2013 15:55:29 GMT]]></title><description><![CDATA[<p>Nachtrag: Ich habe mich entschieden das Monitorobjekt aufzugeben und einfach eine kleine Methode <code>synchronized(F f)</code> anzubieten, die das gleiche macht.</p>
<pre><code class="language-cpp">template&lt;typename F&gt;
void synchronized(F&amp; f)
{
    boost::lock_guard&lt;boost::mutex&gt; lock(m_);
    c_.notify_all();
    f(q_);
}
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2294524</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2294524</guid><dc:creator><![CDATA[knivil]]></dc:creator><pubDate>Tue, 29 Jan 2013 15:55:29 GMT</pubDate></item><item><title><![CDATA[Reply to Code review von synchronized queue on Tue, 29 Jan 2013 16:16:58 GMT]]></title><description><![CDATA[<p>knivil schrieb:</p>
<blockquote>
<p>Korrekt, das wird im Monitor geaendert. Wie sieht das bei push aus, wenn 2 Elemente mittels push ohne Kontextwechsel eingefuegt werden und zwei Konsumer warten. Wird dann auch nur einer aufgeweckt? Ich glaube da muss ich nochmal im Standard zu pthread und boost nachlesen.</p>
</blockquote>
<p>Ich bin mir 95% sicher dass das kein Problem macht.<br />
Aber lies es im Standard nach, garantieren kann ich es dir nicht.</p>
<p>Falls der Standard doch doof sein sollte kann man als Workaround den aufgeweckten Popper vor dem Unlock nochmal checken lassen ob die Queue noch Elemente enthält, und falls ja nochmal <code>notify_one</code> aufrufen lassen.</p>
<p>In Fällen wo immer viele Popper warten, aber die neuen Einträge immer nur langsam dahertröpfeln könnte das performanceschonender sein als ein notify_all.<br />
(Wobei es natürlich in Fällen wo nur ein Popper wartet sehr gute Chancen hat eine Spur langsamer zu sein.)</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2294526</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2294526</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Tue, 29 Jan 2013 16:16:58 GMT</pubDate></item><item><title><![CDATA[Reply to Code review von synchronized queue on Tue, 29 Jan 2013 18:15:08 GMT]]></title><description><![CDATA[<p>Falls es da immer noch um die Message Queue von <a href="http://www.c-plusplus.net/forum/313265" rel="nofollow">hier</a> geht und du durch diese Queue einfach nur Threads mit Arbeit versorgen willst, möchte ich auch mal die Möglichkeit in den Raum werfen, die Queue völlig lock-free als einfachen Ring Buffer zu implementieren.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2294550</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2294550</guid><dc:creator><![CDATA[dot]]></dc:creator><pubDate>Tue, 29 Jan 2013 18:15:08 GMT</pubDate></item></channel></rss>