<?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[[gelöst] dtor von threadsafe_list aus &amp;quot;C++ Concurrency in Action&amp;quot;: Warum remove_if?]]></title><description><![CDATA[<p>Hallo zusammen,</p>
<p>ich lese gerade &quot;C++ Concurrency in Action: Practical Multithreading&quot; von Anthony Williams und verstehe den Sinn des custom destructors seiner threadsafe_list aus Listing 6.13 nicht.</p>
<p>Für die, die das Buch nicht haben: Die Liste, die er da beispielhaft vorstellt ist für die Nutzung in einer thread safe lookup table mit möglichst viel concurrency durch fine grained locks gedacht.</p>
<p>Mir leuchtet nicht ein, wieso der dtor nicht einfach der vom compiler generierte -ßdefault sein kann. Die Liste würde durch die unique_ptr dann doch ganz normal von hinten nach vorne aufgeräumt und alles wäre gut, oder?<br />
Klar, falls noch ein anderer Thread irgendwas auf der Liste macht wär das doof, aber generell sind die die concurrent container im Buch eigentlich so designed, dass vor Begin der Zerstörung jegliche Nutzung abgeschlossen zu sein hat, weshalb hier eigentlich auch kein UB durch das zerstören einer noch gelockten Mutex drohen sollte.<br />
Ist das also nur ein zusätzliches Sicherheitsding, oder übersehe ich irgendwas fundamentales?</p>
<pre><code>template&lt;typename T&gt;
class threadsafe_list
{
	struct node
	{
		std::mutex m;
		std::shared_ptr&lt;T&gt; data;
		std::unique_ptr&lt;node&gt; next;
		node():
			next()
		{}

		node(T const&amp; value):
			data(std::make_shared&lt;T&gt;(value))
		{}
	};

	node head;

public:
	threadsafe_list()
	{}

	~threadsafe_list()
	{
		remove_if([](node const&amp;){return true;});
	}

	threadsafe_list(threadsafe_list const&amp; other)=delete;
	threadsafe_list&amp; operator=(threadsafe_list const&amp; other)=delete;

	void push_front(T const&amp; value)
	{
		std::unique_ptr&lt;node&gt; new_node(new node(value));
		std::lock_guard&lt;std::mutex&gt; lk(head.m);
		new_node-&gt;next=std::move(head.next);
		head.next=std::move(new_node);
	}

	template&lt;typename Function&gt;
	void for_each(Function f)
	{
		node* current=&amp;head;
		std::unique_lock&lt;std::mutex&gt; lk(head.m);
		while(node* const next=current-&gt;next.get())
		{
			std::unique_lock&lt;std::mutex&gt; next_lk(next-&gt;m);
			lk.unlock();
			f(*next-&gt;data);
			current=next;
			lk=std::move(next_lk);
		}
	}

	template&lt;typename Predicate&gt;
	std::shared_ptr&lt;T&gt; find_first_if(Predicate p)
	{
		node* current=&amp;head;
		std::unique_lock&lt;std::mutex&gt; lk(head.m);
		while(node* const next=current-&gt;next.get())
		{
			std::unique_lock&lt;std::mutex&gt; next_lk(next-&gt;m);
			lk.unlock();
			if(p(*next-&gt;data))
			{
				return next-&gt;data;
			}
			current=next;
			lk=std::move(next_lk);
		}
		return std::shared_ptr&lt;T&gt;();
	}

	template&lt;typename Predicate&gt;
	void remove_if(Predicate p)
	{
		node* current=&amp;head;
		std::unique_lock&lt;std::mutex&gt; lk(head.m);
		while(node* const next=current-&gt;next.get())
		{
			std::unique_lock&lt;std::mutex&gt; next_lk(next-&gt;m);
			if(p(*next-&gt;data))
			{
				std::unique_ptr&lt;node&gt; old_next=std::move(current-&gt;next);
				current-&gt;next=std::move(next-&gt;next);
				next_lk.unlock();
			}
			else
			{
				lk.unlock();
				current=next;
				lk=std::move(next_lk);
			}
		}
	}
};
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/topic/312333/gelöst-dtor-von-threadsafe_list-aus-quot-c-concurrency-in-action-quot-warum-remove_if</link><generator>RSS for Node</generator><lastBuildDate>Sun, 02 Aug 2026 23:45:44 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/312333.rss" rel="self" type="application/rss+xml"/><pubDate>Wed, 02 Jan 2013 09:35:45 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to [gelöst] dtor von threadsafe_list aus &amp;quot;C++ Concurrency in Action&amp;quot;: Warum remove_if? on Wed, 02 Jan 2013 13:30:20 GMT]]></title><description><![CDATA[<p>Hallo zusammen,</p>
<p>ich lese gerade &quot;C++ Concurrency in Action: Practical Multithreading&quot; von Anthony Williams und verstehe den Sinn des custom destructors seiner threadsafe_list aus Listing 6.13 nicht.</p>
<p>Für die, die das Buch nicht haben: Die Liste, die er da beispielhaft vorstellt ist für die Nutzung in einer thread safe lookup table mit möglichst viel concurrency durch fine grained locks gedacht.</p>
<p>Mir leuchtet nicht ein, wieso der dtor nicht einfach der vom compiler generierte -ßdefault sein kann. Die Liste würde durch die unique_ptr dann doch ganz normal von hinten nach vorne aufgeräumt und alles wäre gut, oder?<br />
Klar, falls noch ein anderer Thread irgendwas auf der Liste macht wär das doof, aber generell sind die die concurrent container im Buch eigentlich so designed, dass vor Begin der Zerstörung jegliche Nutzung abgeschlossen zu sein hat, weshalb hier eigentlich auch kein UB durch das zerstören einer noch gelockten Mutex drohen sollte.<br />
Ist das also nur ein zusätzliches Sicherheitsding, oder übersehe ich irgendwas fundamentales?</p>
<pre><code>template&lt;typename T&gt;
class threadsafe_list
{
	struct node
	{
		std::mutex m;
		std::shared_ptr&lt;T&gt; data;
		std::unique_ptr&lt;node&gt; next;
		node():
			next()
		{}

		node(T const&amp; value):
			data(std::make_shared&lt;T&gt;(value))
		{}
	};

	node head;

public:
	threadsafe_list()
	{}

	~threadsafe_list()
	{
		remove_if([](node const&amp;){return true;});
	}

	threadsafe_list(threadsafe_list const&amp; other)=delete;
	threadsafe_list&amp; operator=(threadsafe_list const&amp; other)=delete;

	void push_front(T const&amp; value)
	{
		std::unique_ptr&lt;node&gt; new_node(new node(value));
		std::lock_guard&lt;std::mutex&gt; lk(head.m);
		new_node-&gt;next=std::move(head.next);
		head.next=std::move(new_node);
	}

	template&lt;typename Function&gt;
	void for_each(Function f)
	{
		node* current=&amp;head;
		std::unique_lock&lt;std::mutex&gt; lk(head.m);
		while(node* const next=current-&gt;next.get())
		{
			std::unique_lock&lt;std::mutex&gt; next_lk(next-&gt;m);
			lk.unlock();
			f(*next-&gt;data);
			current=next;
			lk=std::move(next_lk);
		}
	}

	template&lt;typename Predicate&gt;
	std::shared_ptr&lt;T&gt; find_first_if(Predicate p)
	{
		node* current=&amp;head;
		std::unique_lock&lt;std::mutex&gt; lk(head.m);
		while(node* const next=current-&gt;next.get())
		{
			std::unique_lock&lt;std::mutex&gt; next_lk(next-&gt;m);
			lk.unlock();
			if(p(*next-&gt;data))
			{
				return next-&gt;data;
			}
			current=next;
			lk=std::move(next_lk);
		}
		return std::shared_ptr&lt;T&gt;();
	}

	template&lt;typename Predicate&gt;
	void remove_if(Predicate p)
	{
		node* current=&amp;head;
		std::unique_lock&lt;std::mutex&gt; lk(head.m);
		while(node* const next=current-&gt;next.get())
		{
			std::unique_lock&lt;std::mutex&gt; next_lk(next-&gt;m);
			if(p(*next-&gt;data))
			{
				std::unique_ptr&lt;node&gt; old_next=std::move(current-&gt;next);
				current-&gt;next=std::move(next-&gt;next);
				next_lk.unlock();
			}
			else
			{
				lk.unlock();
				current=next;
				lk=std::move(next_lk);
			}
		}
	}
};
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2285220</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2285220</guid><dc:creator><![CDATA[Dobi]]></dc:creator><pubDate>Wed, 02 Jan 2013 13:30:20 GMT</pubDate></item><item><title><![CDATA[Reply to [gelöst] dtor von threadsafe_list aus &amp;quot;C++ Concurrency in Action&amp;quot;: Warum remove_if? on Wed, 02 Jan 2013 10:02:48 GMT]]></title><description><![CDATA[<p>Würde im Defaultdestruktur ein Nodenmutex gesperrt?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2285230</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2285230</guid><dc:creator><![CDATA[manni66]]></dc:creator><pubDate>Wed, 02 Jan 2013 10:02:48 GMT</pubDate></item><item><title><![CDATA[Reply to [gelöst] dtor von threadsafe_list aus &amp;quot;C++ Concurrency in Action&amp;quot;: Warum remove_if? on Wed, 02 Jan 2013 10:03:03 GMT]]></title><description><![CDATA[<p>Die Lambda, die im Destruktor dem remove_if übgeben wird, gibt doch immer true zurück. die Liste wird also einfach so abgeräumt. Eine andere remove mthode brint die Klasse ja nicht mit.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2285231</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2285231</guid><dc:creator><![CDATA[Praedikat]]></dc:creator><pubDate>Wed, 02 Jan 2013 10:03:03 GMT</pubDate></item><item><title><![CDATA[Reply to [gelöst] dtor von threadsafe_list aus &amp;quot;C++ Concurrency in Action&amp;quot;: Warum remove_if? on Wed, 02 Jan 2013 10:07:35 GMT]]></title><description><![CDATA[<p>manni66 schrieb:</p>
<blockquote>
<p>Würde im Defaultdestruktur ein Nodenmutex gesperrt?</p>
</blockquote>
<p>Nein, aber müsste es?</p>
<p>Praedikat schrieb:</p>
<blockquote>
<p>Die Lambda, die im Destruktor dem remove_if übgeben wird, gibt doch immer true zurück. die Liste wird also einfach so abgeräumt. Eine andere remove mthode brint die Klasse ja nicht mit.</p>
</blockquote>
<p>Ja, schon klar, aber wieso lässt man sie nicht auf &quot;natürlichem Weg&quot; aufräumen?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2285232</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2285232</guid><dc:creator><![CDATA[Dobi]]></dc:creator><pubDate>Wed, 02 Jan 2013 10:07:35 GMT</pubDate></item><item><title><![CDATA[Reply to [gelöst] dtor von threadsafe_list aus &amp;quot;C++ Concurrency in Action&amp;quot;: Warum remove_if? on Wed, 02 Jan 2013 10:21:33 GMT]]></title><description><![CDATA[<p>Dobi schrieb:</p>
<blockquote>
<p>übersehe ich irgendwas fundamentales?</p>
</blockquote>
<p>Die Zerstörung eines mutex ist selbst nicht threadsafe. Mithin muss der zerstörende Thread für vorherige Synchronisation sorgen, andernfalls entstünde eine Race Condition (jedenfalls potentiell, das hängt davon ab, wie genau sicher gestellt wurde, dass alle operationen auf der Liste beendet sind), falls zuletzt ein anderer Thread den Mutex besessen hat.<br />
Ein anderer Grund ist möglicherweise der, dass der Defaultkonstruktor die Liste rekursiv löscht, was potentiell zu einem Stacküberlauf führen könnte.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2285234</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2285234</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Wed, 02 Jan 2013 10:21:33 GMT</pubDate></item><item><title><![CDATA[Reply to [gelöst] dtor von threadsafe_list aus &amp;quot;C++ Concurrency in Action&amp;quot;: Warum remove_if? on Wed, 02 Jan 2013 10:22:05 GMT]]></title><description><![CDATA[<p>Dobi schrieb:</p>
<blockquote>
<p>manni66 schrieb:</p>
<blockquote>
<p>Würde im Defaultdestruktur ein Nodenmutex gesperrt?</p>
</blockquote>
<p>Nein, aber müsste es?</p>
</blockquote>
<ol>
<li>
<p>ein Mutex garantiert, dass alle Prozessoren den gleichen Speicherinhalt sehen. Vor C++ 11 war das auf jeden Fall notwendig, soweit ich weiss ändert das neue Speichermodell daran nichts, wenn man keine Atomic Variablen benutzt.</p>
</li>
<li>
<p>warum sollte man darauf hoffen, dass schon alles gut geht, wenn man es absichern kann?</p>
</li>
</ol>
]]></description><link>https://www.c-plusplus.net/forum/post/2285235</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2285235</guid><dc:creator><![CDATA[manni66]]></dc:creator><pubDate>Wed, 02 Jan 2013 10:22:05 GMT</pubDate></item><item><title><![CDATA[Reply to [gelöst] dtor von threadsafe_list aus &amp;quot;C++ Concurrency in Action&amp;quot;: Warum remove_if? on Wed, 02 Jan 2013 10:30:02 GMT]]></title><description><![CDATA[<p>@manni66:</p>
<ol>
<li>Nach dem Zerstören sollte sich eigentlich kein Prozessor den Speicherinhalt noch angucken. <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="😉"
    /></li>
<li>Es wäre ja kein blindes Hoffen, weil man ja genau wüsste, in welcher Reihenfolge die Liste im default dtor zerstört würde, was ja auch unter der oben genannten Voraussetzung kein Problem wäre.</li>
</ol>
<p><a class="plugin-mentions-user plugin-mentions-a" href="https://www.c-plusplus.net/forum/uid/6642">@camper</a>: Na gut, ich hatte ihn so verstanden, dass für alle dtors in seinen Containern da die Grundvoraussetzung gilt, dass nach dem Start der Zerstörung kein anderer Thread mehr drauf zugreift. Wär also dann halt nur ein zusätzliches Sicherheitsding. Wundert mich halt, weil er das bei seinen anderen Containern (zb beim Stack) halt nicht macht. Der würde einem auch um die Ohren fliegen wenn man ihn zerstört während jemand anders noch drauf hantiert.<br />
Stacküberlauf ist auch ne interessante Idee. <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f642.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--slightly_smiling_face"
      title=":)"
      alt="🙂"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2285239</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2285239</guid><dc:creator><![CDATA[Dobi]]></dc:creator><pubDate>Wed, 02 Jan 2013 10:30:02 GMT</pubDate></item><item><title><![CDATA[Reply to [gelöst] dtor von threadsafe_list aus &amp;quot;C++ Concurrency in Action&amp;quot;: Warum remove_if? on Wed, 02 Jan 2013 10:36:48 GMT]]></title><description><![CDATA[<p>Dobi schrieb:</p>
<blockquote>
<p>@manni66:</p>
<ol>
<li>Nach dem Zerstören sollte sich eigentlich kein Prozessor den Speicherinhalt noch angucken. <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="😉"
    /></li>
</ol>
</blockquote>
<p>Der zerstörende Prozess sollte aber das zuletzt geschriebene sehen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2285243</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2285243</guid><dc:creator><![CDATA[manni66]]></dc:creator><pubDate>Wed, 02 Jan 2013 10:36:48 GMT</pubDate></item><item><title><![CDATA[Reply to [gelöst] dtor von threadsafe_list aus &amp;quot;C++ Concurrency in Action&amp;quot;: Warum remove_if? on Wed, 02 Jan 2013 10:38:23 GMT]]></title><description><![CDATA[<p>Muss natürlich Thread und nicht Prozess heissen</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2285244</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2285244</guid><dc:creator><![CDATA[manni66]]></dc:creator><pubDate>Wed, 02 Jan 2013 10:38:23 GMT</pubDate></item><item><title><![CDATA[Reply to [gelöst] dtor von threadsafe_list aus &amp;quot;C++ Concurrency in Action&amp;quot;: Warum remove_if? on Wed, 02 Jan 2013 10:43:41 GMT]]></title><description><![CDATA[<p>manni66 schrieb:</p>
<blockquote>
<p>Der zerstörende Thread sollte aber das zuletzt geschriebene sehen.</p>
</blockquote>
<p>Alles, was geschrieben wurde, war dabei doch eh schon in Mutexe verpackt. Die dann beim Zerstören noch ein zweites mal alle durchzulocken, ist also unnötig.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2285247</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2285247</guid><dc:creator><![CDATA[Dobi]]></dc:creator><pubDate>Wed, 02 Jan 2013 10:43:41 GMT</pubDate></item><item><title><![CDATA[Reply to [gelöst] dtor von threadsafe_list aus &amp;quot;C++ Concurrency in Action&amp;quot;: Warum remove_if? on Wed, 02 Jan 2013 10:52:28 GMT]]></title><description><![CDATA[<p>Dobi schrieb:</p>
<blockquote>
<p>manni66 schrieb:</p>
<blockquote>
<p>Der zerstörende Thread sollte aber das zuletzt geschriebene sehen.</p>
</blockquote>
<p>Alles, was geschrieben wurde, war dabei doch eh schon in Mutexe verpackt. Die dann beim Zerstören noch ein zweites mal alle durchzulocken, ist also unnötig.</p>
</blockquote>
<p>Nein, so funktioniert das nicht. Nachdem ein Mutex gesperrt wurde, ist garantiert, dass der sperrende Thread alles &quot;sieht&quot;, was vorher geschreiben wurde. Mehr nicht!</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2285248</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2285248</guid><dc:creator><![CDATA[manni66]]></dc:creator><pubDate>Wed, 02 Jan 2013 10:52:28 GMT</pubDate></item><item><title><![CDATA[Reply to [gelöst] dtor von threadsafe_list aus &amp;quot;C++ Concurrency in Action&amp;quot;: Warum remove_if? on Wed, 02 Jan 2013 11:08:50 GMT]]></title><description><![CDATA[<p>Ah ok, das Locken einer Mutex hat acquire-semantik und das Unlocken zwar release-Semantik, aber wenn A schreibt, dann released und B danach nicht acquired, sieht B das was A geschrieben hat nicht unbedingt. Und hier im dtor muss der zerstörende Thread sehen, was andere vorher geschrieben haben, weil T ein Typ sein könnte, der in seinem dtor eventuell noch etwas tun will, richtig? <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f642.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--slightly_smiling_face"
      title=":)"
      alt="🙂"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2285255</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2285255</guid><dc:creator><![CDATA[Dobi]]></dc:creator><pubDate>Wed, 02 Jan 2013 11:08:50 GMT</pubDate></item><item><title><![CDATA[Reply to [gelöst] dtor von threadsafe_list aus &amp;quot;C++ Concurrency in Action&amp;quot;: Warum remove_if? on Wed, 02 Jan 2013 11:31:41 GMT]]></title><description><![CDATA[<p>Ja, so meinte ich das.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2285272</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2285272</guid><dc:creator><![CDATA[manni66]]></dc:creator><pubDate>Wed, 02 Jan 2013 11:31:41 GMT</pubDate></item><item><title><![CDATA[Reply to [gelöst] dtor von threadsafe_list aus &amp;quot;C++ Concurrency in Action&amp;quot;: Warum remove_if? on Wed, 02 Jan 2013 11:53:09 GMT]]></title><description><![CDATA[<p>Super, danke, das klingt sehr vernünftig.<br />
Edit: Oh, es geht ja nicht nur um die dtors der Instanzen von T, also von node::data, sondern auch darum, dass Änderungen an den besitzenden Verbindungszeigern node::next sichtbar sind. Wunderfein. <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f642.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--slightly_smiling_face"
      title=":)"
      alt="🙂"
    /></p>
<p>Warum er das dann beispielsweise bei seiner threadsafe_queue nicht macht, weiß ich zwar nicht, aber das ist ja ein anderes Thema.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2285282</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2285282</guid><dc:creator><![CDATA[Dobi]]></dc:creator><pubDate>Wed, 02 Jan 2013 11:53:09 GMT</pubDate></item></channel></rss>