<?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[Multipurpose Nachricht zwischen Threads]]></title><description><![CDATA[<p>Hi</p>
<p>also ich habe ein System aus verschiedenen WorkerThreads, die untereinander über ThreadSafe-Queues kommunizieren.</p>
<p>Ich transportiere auf diesem Wege also viele verschiedene Objekte zwischen den Workern hin und her.</p>
<p>Bisher hatte ich immer eine Message als Basisklasse und habe 10-100 spezialisierte Messages davon abgeleitet und diese durch die Queues gescheucht.</p>
<p>Nun ist das bei kleinen Projekten ok. Wenn aber das Projekte größer wird und die spezialisierten Messages immer größer werden, nervt das Klassengebastel.</p>
<p>Daher wollte ich mir eine Message bauen, die erstmal grundsätzlich aus einem Buffer ( z.b. std::vector&lt;char&gt; oder std::string ) besteht, der beliebig vergrößert werden kann.</p>
<p>In diesen Buffer wollte ich dann meine Objekte reinswappen.</p>
<p>Erzeugung einer Message sollte dann etwa so aussehen:</p>
<pre><code>std::shared_ptr&lt;SomeType&gt; FooTransport;
unsigned bla = 1337;
...

auto msg = std::make_shared&lt;Message&gt; ( 1 );
msg-&gt;push&lt;SomeType&gt; ( FooTransport );
msg-&gt;push&lt;unsigned&gt; ( bla );

...

versende( msg );
</code></pre>
<p>Wären die Objekte alle einfache Pointer, könnte ich die Daten einfach in den Buffer kopieren und den Pointer ausnullen, damit er nach dem &quot;versende&quot;-Aufruf unbenutzbar ist.</p>
<p>Bei PODs wie z.B. unsigned kann ich auch einfach swappen.</p>
<p>Aber was mache ich mit z.B. shared_ptr&lt;...&gt;-Typen oder KlassenObjekten?<br />
Die kann ich doch nicht einfach swappen? Im Beispiel wird ja dann 'FooTransport' mit dem bisherigen Inhalt des Buffers ( undefiniert ) befüllt und wird somit höchstwahrscheinlich hinterher total schrott / undefined sein.</p>
<p>Ist das Problem für euch nachvollziehbar? Vorschläge?</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/333705/multipurpose-nachricht-zwischen-threads</link><generator>RSS for Node</generator><lastBuildDate>Sun, 26 Apr 2026 18:20:59 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/333705.rss" rel="self" type="application/rss+xml"/><pubDate>Sat, 25 Jul 2015 18:36:38 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Multipurpose Nachricht zwischen Threads on Sat, 25 Jul 2015 18:36:38 GMT]]></title><description><![CDATA[<p>Hi</p>
<p>also ich habe ein System aus verschiedenen WorkerThreads, die untereinander über ThreadSafe-Queues kommunizieren.</p>
<p>Ich transportiere auf diesem Wege also viele verschiedene Objekte zwischen den Workern hin und her.</p>
<p>Bisher hatte ich immer eine Message als Basisklasse und habe 10-100 spezialisierte Messages davon abgeleitet und diese durch die Queues gescheucht.</p>
<p>Nun ist das bei kleinen Projekten ok. Wenn aber das Projekte größer wird und die spezialisierten Messages immer größer werden, nervt das Klassengebastel.</p>
<p>Daher wollte ich mir eine Message bauen, die erstmal grundsätzlich aus einem Buffer ( z.b. std::vector&lt;char&gt; oder std::string ) besteht, der beliebig vergrößert werden kann.</p>
<p>In diesen Buffer wollte ich dann meine Objekte reinswappen.</p>
<p>Erzeugung einer Message sollte dann etwa so aussehen:</p>
<pre><code>std::shared_ptr&lt;SomeType&gt; FooTransport;
unsigned bla = 1337;
...

auto msg = std::make_shared&lt;Message&gt; ( 1 );
msg-&gt;push&lt;SomeType&gt; ( FooTransport );
msg-&gt;push&lt;unsigned&gt; ( bla );

...

versende( msg );
</code></pre>
<p>Wären die Objekte alle einfache Pointer, könnte ich die Daten einfach in den Buffer kopieren und den Pointer ausnullen, damit er nach dem &quot;versende&quot;-Aufruf unbenutzbar ist.</p>
<p>Bei PODs wie z.B. unsigned kann ich auch einfach swappen.</p>
<p>Aber was mache ich mit z.B. shared_ptr&lt;...&gt;-Typen oder KlassenObjekten?<br />
Die kann ich doch nicht einfach swappen? Im Beispiel wird ja dann 'FooTransport' mit dem bisherigen Inhalt des Buffers ( undefiniert ) befüllt und wird somit höchstwahrscheinlich hinterher total schrott / undefined sein.</p>
<p>Ist das Problem für euch nachvollziehbar? Vorschläge?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2460999</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2460999</guid><dc:creator><![CDATA[It0101]]></dc:creator><pubDate>Sat, 25 Jul 2015 18:36:38 GMT</pubDate></item><item><title><![CDATA[Reply to Multipurpose Nachricht zwischen Threads on Sat, 25 Jul 2015 18:51:49 GMT]]></title><description><![CDATA[<p>Zusatzhinweis:</p>
<p>Lösung muss auf jeden Fall performant sein, also irgendwelche Kopiergeschichten fallen aus.</p>
<p>Ein schlampige Lösung würde ja ohne swap gehen, in dem man einfach das zu transportierende Objekt im Heap anlegt ( über Kopierkonstruktor ) und dann nur die Adresse in den Buffer kopiert.</p>
<p>Aber diese Lösung wollte ich eigentlich nicht, daher meine Suche nach einer swap/move/etc.-Lösung.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2461001</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2461001</guid><dc:creator><![CDATA[It0101]]></dc:creator><pubDate>Sat, 25 Jul 2015 18:51:49 GMT</pubDate></item><item><title><![CDATA[Reply to Multipurpose Nachricht zwischen Threads on Sat, 25 Jul 2015 19:34:31 GMT]]></title><description><![CDATA[<p>Also das hier funzt schonmal nicht:</p>
<pre><code>template&lt;typename T&gt; void push( T &amp;obj, char *&amp;act )
{
    *( (T*)act ) = std::move( obj );
    act += sizeof( T );
}

template&lt;typename T&gt; void pop( T &amp;obj, char *&amp;act )
{
    obj = std::move( *( (T*)act ) );
    act += sizeof( T );
}

int main()
{
    std::string Message;
    Message.resize( 1000 );
    char *pos = (char*)Message.data();

    // reinschreiben
    std::string TestObject = &quot;foobar&quot;;
    push&lt;std::string&gt; ( TestObject, pos );

    // auslesen
    pos = (char*)Message.data();
    std::string out;
    pop&lt;std::string&gt; ( out, pos );

    std::cout &lt;&lt; out &lt;&lt; &quot;\n&quot;;

    return 0;
}
</code></pre>
<p>Gibt in der ersten Zeile der Funktion &quot;push&lt;T&gt;&quot; einen SegFault...</p>
<p>Aber zumindest so in der Richtung dachte ich mir das.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2461006</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2461006</guid><dc:creator><![CDATA[It0101]]></dc:creator><pubDate>Sat, 25 Jul 2015 19:34:31 GMT</pubDate></item><item><title><![CDATA[Reply to Multipurpose Nachricht zwischen Threads on Sat, 25 Jul 2015 19:59:59 GMT]]></title><description><![CDATA[<p>So würde man das machen:</p>
<pre><code class="language-cpp">template &lt;typename T&gt; void push(T&amp;&amp; obj, char *&amp;act) {
  using type = typename std::remove_reference&lt;T&gt;::type;
  new (act) type(std::forward&lt;T&gt;(obj));
  act += sizeof(type);
}

template &lt;typename T&gt; T&amp; top(char *act) {
  return *reinterpret_cast&lt;T*&gt;(act);
}

template &lt;typename T&gt; void pop(char *&amp;act) {
  top&lt;T&gt;(act).~T();
  act += sizeof(T);
}

int main() {
  std::string Message;
  Message.resize(1000);
  char *pos = (char *)Message.data();

  // reinschreiben
  std::string TestObject = &quot;foobar&quot;;
  push(std::move(TestObject), pos);

  // auslesen
  pos = (char *)Message.data();
  auto out = std::move(top&lt;std::string&gt;(pos));
  pop&lt;std::string&gt;(pos);

  std::cout &lt;&lt; out &lt;&lt; &quot;\n&quot;;
}
</code></pre>
<p>Du hast vergessen, Konstruktor und Destruktor aufzurufen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2461007</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2461007</guid><dc:creator><![CDATA[sicherohneausnahme]]></dc:creator><pubDate>Sat, 25 Jul 2015 19:59:59 GMT</pubDate></item><item><title><![CDATA[Reply to Multipurpose Nachricht zwischen Threads on Sat, 25 Jul 2015 20:07:07 GMT]]></title><description><![CDATA[<p>Wow, das funzt jetzt aber. Danke schön.<br />
Ich muss mir jetzt aber erstmal anschauen, was du da in den Funktionen so wildes treibst. Da muss ich erstmal Forschung betreiben <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>Danke erstmal <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f603.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--grinning_face_with_big_eyes"
      title=":D"
      alt="😃"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2461008</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2461008</guid><dc:creator><![CDATA[It0101]]></dc:creator><pubDate>Sat, 25 Jul 2015 20:07:07 GMT</pubDate></item><item><title><![CDATA[Reply to Multipurpose Nachricht zwischen Threads on Sat, 25 Jul 2015 20:17:38 GMT]]></title><description><![CDATA[<p>It0101 schrieb:</p>
<blockquote>
<p>Da muss ich erstmal Forschung betreiben <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>
</blockquote>
<p>Das Stichwort lautet <em>placement new</em>, wenn du es noch nicht gefunden hast. Der Rest mit <code>remove_reference</code> und <code>forward</code> ist nur drumherum.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2461009</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2461009</guid><dc:creator><![CDATA[sebi707]]></dc:creator><pubDate>Sat, 25 Jul 2015 20:17:38 GMT</pubDate></item><item><title><![CDATA[Reply to Multipurpose Nachricht zwischen Threads on Sat, 25 Jul 2015 20:35:32 GMT]]></title><description><![CDATA[<p>Ok danke. Da hab ich offensichtlich Defizite die ich jetzt beheben muss <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/2461010</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2461010</guid><dc:creator><![CDATA[It0101]]></dc:creator><pubDate>Sat, 25 Jul 2015 20:35:32 GMT</pubDate></item><item><title><![CDATA[Reply to Multipurpose Nachricht zwischen Threads on Sat, 25 Jul 2015 23:46:54 GMT]]></title><description><![CDATA[<p>Zusätzlich sollte in <code>push</code> , <code>top</code> und <code>pop</code> noch <a href="http://en.cppreference.com/w/cpp/memory/align" rel="nofollow">std::align</a> verwendet werden.<br />
Sonst bekommst du auf einigen Plattformen Probleme.</p>
<p>ps:<br />
@sicherohneausnahme<br />
<code>remove_reference</code> sollte hier nicht nötig sein. IIRC gilt <code>sizeof(T) == sizeof(T&amp;) &amp;&amp; sizeof(T) == sizeof(T&amp;&amp;)</code></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2461019</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2461019</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Sat, 25 Jul 2015 23:46:54 GMT</pubDate></item><item><title><![CDATA[Reply to Multipurpose Nachricht zwischen Threads on Sun, 26 Jul 2015 10:10:25 GMT]]></title><description><![CDATA[<p>hustbaer schrieb:</p>
<blockquote>
<p><code>remove_reference</code> sollte hier nicht nötig sein. IIRC gilt <code>sizeof(T) == sizeof(T&amp;) &amp;&amp; sizeof(T) == sizeof(T&amp;&amp;)</code></p>
</blockquote>
<p>Das mag zwar sein, allerdings benötigt man den Typ ohne Referenz für das placement new.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2461027</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2461027</guid><dc:creator><![CDATA[sebi707]]></dc:creator><pubDate>Sun, 26 Jul 2015 10:10:25 GMT</pubDate></item><item><title><![CDATA[Reply to Multipurpose Nachricht zwischen Threads on Sun, 26 Jul 2015 15:56:43 GMT]]></title><description><![CDATA[<p>sebi707 schrieb:</p>
<blockquote>
<p>Das mag zwar sein, allerdings benötigt man den Typ ohne Referenz für das placement new.</p>
</blockquote>
<p><img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f4a1.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--light_bulb"
      title=":bulb:"
      alt="💡"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2461054</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2461054</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Sun, 26 Jul 2015 15:56:43 GMT</pubDate></item><item><title><![CDATA[Reply to Multipurpose Nachricht zwischen Threads on Sun, 26 Jul 2015 17:27:39 GMT]]></title><description><![CDATA[<p>hustbaer schrieb:</p>
<blockquote>
<p>sebi707 schrieb:</p>
<blockquote>
<p>Das mag zwar sein, allerdings benötigt man den Typ ohne Referenz für das placement new.</p>
</blockquote>
<p><img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f4a1.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--light_bulb"
      title=":bulb:"
      alt="💡"
    /></p>
</blockquote>
<p><img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f4a1.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--light_bulb"
      title=":bulb:"
      alt="💡"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2461056</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2461056</guid><dc:creator><![CDATA[aha!]]></dc:creator><pubDate>Sun, 26 Jul 2015 17:27:39 GMT</pubDate></item><item><title><![CDATA[Reply to Multipurpose Nachricht zwischen Threads on Mon, 27 Jul 2015 03:43:06 GMT]]></title><description><![CDATA[<p>Hi!</p>
<p>Nur so als Anregung: Ich verwende gerne eine Basisklasse für sehr allgemeine Arbeits-Threads, die nicht viel anderes machen als <code>std::function</code> -Objekte in einem <code>queue</code> der Reihe nach auszuführen. So kann man dem Thread bequem beliebige Aufgaben geben, oder bei Bedarf die Basisklasse auch für spezialisierte Aufgaben erweitern. Ich weiss zwar nicht, was für Briefe sich deine Threads so schreiben, aber auf so einem function-Arbeitstread kann man durchaus ein Message-System aufsetzen. Das, was du mit deiner &quot;Multipurpose&quot;-Nachricht erreichen möchtes (so wie ich es verstanden habe) lasse ich dabei einfach von <code>std::bind</code> erledigen. Als Prototyp sähe das Ganze dann grob etwa so aus:</p>
<pre><code>#include &lt;functional&gt;
#include &lt;string&gt;
#include &lt;memory&gt;
#include &lt;mutex&gt;
#include &lt;deque&gt;

struct Object 
{
    void print()
    {
        std::cout &lt;&lt; &quot;Hallo vom Objekt!&quot; &lt;&lt; std::endl;
    }
};

class WorkerThread
{
    public:
        typedef std::function&lt;void()&gt; TaskFunction;

        void enqueue(TaskFunction taskFunction)
        {
            std::lock_guard&lt;std::mutex&gt; lock(queueMutex);
            taskQueue.emplace_back(std::move(taskFunction));
        }

        void threadFunction()
        {
            {
                std::lock_guard&lt;std::mutex&gt; lock(queueMutex);
                while (!taskQueue.empty())
                {
                    taskQueue.front()();
                    taskQueue.pop_front();
                }
            }

            // Warten, bis queue nicht mehr leer (condition variable o.ä.)
        }

    private:
        std::mutex queueMutex;
        std::deque&lt;TaskFunction&gt; taskQueue;
};

class MessageThread : public WorkerThread
{
    public:
        class Message
        {
            friend class MessageThread;
            protected:
                typedef std::function&lt;void(MessageThread* thread)&gt; MessageFunction;

                Message(MessageFunction messageFunction)
                : messageFunction(std::move(messageFunction))
                {
                }

            private:
                MessageFunction messageFunction;
        };

        class Message1 : public Message
        {
            public:
                Message1(int arg1, std::string arg2, const std::shared_ptr&lt;Object&gt;&amp; arg3)
                : Message(std::bind(&amp;MessageThread::message1Function, std::placeholders::_1, arg1, arg2, arg3))
                {
                }
        };        

        void enqueue(const Message&amp; message)
        {
            WorkerThread::enqueue(std::bind(message.messageFunction, this));
        }

    private:
        void message1Function(int arg1, std::string arg2, const std::shared_ptr&lt;Object&gt;&amp; object)
        {
            std::cout &lt;&lt; &quot;Nachricht Typ 1 #&quot; &lt;&lt; arg1 &lt;&lt; &quot;: string = &quot; &lt;&lt; arg2 &lt;&lt; std::endl;
            object-&gt;print();
        }
};

int main()
{
    MessageThread thread;

    auto object = std::make_shared&lt;Object&gt;();

    std::cout &lt;&lt; &quot;ENQUEUE&quot; &lt;&lt; std::endl;
    thread.enqueue(MessageThread::Message1(1, &quot;Nachricht 1&quot;, object));
    thread.enqueue(MessageThread::Message1(2, &quot;Nachricht 2&quot;, object));
    thread.enqueue(MessageThread::Message1(3, &quot;Nachricht 3&quot;, object));

    std::cout &lt;&lt; &quot;PROCESS&quot; &lt;&lt; std::endl;
    thread.threadFunction();
}
</code></pre>
<p>Der Code ist natürlich noch zu verfeinern, aber ich denke die Idee kommt rüber.<br />
Vielleicht ist das ja eine etwas bequemer zu implementierende Alternative.</p>
<p>Gruss,<br />
Finnegan</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2461094</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2461094</guid><dc:creator><![CDATA[Finnegan]]></dc:creator><pubDate>Mon, 27 Jul 2015 03:43:06 GMT</pubDate></item></channel></rss>