<?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[std::future in Klasse noch Threadsafe?]]></title><description><![CDATA[<p>Hallo an alle,</p>
<p>ich habe einen Workerthread, der für bestimmte Aufgaben Parameter verwendet. Zur überprüfung ob eine Aufgabe bereits fertig ist, wollte ich ein <em>std::packeged_task</em> bzw. ein <em>std::future</em> verwenden. Soweit gibt es keine Probleme. Da ich im Falle einer Ausnahme im Workerthread die Behandlung im Mainthread machen möchte, eignet sich <em>std::future::get()</em> natürlich hervorragend. Jedoch möchte ich bei einer Ausnahme gerne eine Fehlermeldung passend zu den verwendeten Parametern generieren. Die Idee war, in der Parameterklasse das Rückgabe-future zu speichern. Ich bin mir jetzt jedoch nicht sicher ob das nicht u.U. Threadunsafe ist.<br />
Ich habe mal ein Pseudobeispiel erstellt, damit das Problem verständlicher ist:</p>
<pre><code>#include&lt;functional&gt;
#include&lt;thread&gt;
#include&lt;queue&gt;
#include&lt;mutex&gt;
#include&lt;condition_variable&gt;
#include&lt;future&gt;
#include&lt;memory&gt;
#include&lt;iostream&gt;
#include&lt;string&gt;

using namespace std;

queue&lt;function&lt;void()&gt;&gt; tasks; 
mutex					m;
condition_variable		cv;
bool					shutdown{ false };

void worker_function()
{
	function&lt;void()&gt; task;

	while( true )
	{
		{
			unique_lock&lt;mutex&gt; lock( m );

			while( tasks.empty() &amp;&amp; !shutdown )
				cv.wait( lock );

			if( shutdown )
				return;

			task = move( tasks.front() );
			tasks.pop();
		}

		task();
		task = nullptr;
	}
}

// Ein simples Data-Objekt als Beispiel
struct objekt
{
	string 				   data; // Parameter
	std::future&lt;long long&gt; result; // Ergebnis
};

long long bsp_task( const shared_ptr&lt;objekt&gt;&amp; bsp_data )
{
	return stoll( bsp_data-&gt;data );
}

int main()
{
	thread worker{ worker_function };

	shared_ptr&lt;objekt&gt; shared_data{ make_shared&lt;objekt&gt;() };
	shared_data-&gt;data = &quot;42&quot;;

	auto ptask{ make_shared&lt;std::packaged_task&lt;long long()&gt;&gt;( bind( bsp_task , cref( shared_data ) ) ) };

	shared_data-&gt;result = ptask-&gt;get_future();

	{
		lock_guard&lt;mutex&gt; lock( m );
		tasks.emplace( [ptask] { ( *ptask )(); } );
	}

	cv.notify_one();

	// Hier ist der eigentliche Knackpunkt:
	// Ist der Aufruf von result.get() noch threadsafe, obwohl u.U. auf den data-Member zugegriffen wird (in anderen Beispielen evtl. auch schreibend)
	cout &lt;&lt; shared_data-&gt;result.get() &lt;&lt; endl;

	cin.get();

	{
		lock_guard&lt;mutex&gt; lock( m );
		shutdown = true;
	}
	cv.notify_one();
	worker.join();

	return 0;
}
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/topic/337008/std-future-in-klasse-noch-threadsafe</link><generator>RSS for Node</generator><lastBuildDate>Sat, 18 Apr 2026 13:43:17 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/337008.rss" rel="self" type="application/rss+xml"/><pubDate>Mon, 29 Feb 2016 22:06:32 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to std::future in Klasse noch Threadsafe? on Mon, 29 Feb 2016 22:06:32 GMT]]></title><description><![CDATA[<p>Hallo an alle,</p>
<p>ich habe einen Workerthread, der für bestimmte Aufgaben Parameter verwendet. Zur überprüfung ob eine Aufgabe bereits fertig ist, wollte ich ein <em>std::packeged_task</em> bzw. ein <em>std::future</em> verwenden. Soweit gibt es keine Probleme. Da ich im Falle einer Ausnahme im Workerthread die Behandlung im Mainthread machen möchte, eignet sich <em>std::future::get()</em> natürlich hervorragend. Jedoch möchte ich bei einer Ausnahme gerne eine Fehlermeldung passend zu den verwendeten Parametern generieren. Die Idee war, in der Parameterklasse das Rückgabe-future zu speichern. Ich bin mir jetzt jedoch nicht sicher ob das nicht u.U. Threadunsafe ist.<br />
Ich habe mal ein Pseudobeispiel erstellt, damit das Problem verständlicher ist:</p>
<pre><code>#include&lt;functional&gt;
#include&lt;thread&gt;
#include&lt;queue&gt;
#include&lt;mutex&gt;
#include&lt;condition_variable&gt;
#include&lt;future&gt;
#include&lt;memory&gt;
#include&lt;iostream&gt;
#include&lt;string&gt;

using namespace std;

queue&lt;function&lt;void()&gt;&gt; tasks; 
mutex					m;
condition_variable		cv;
bool					shutdown{ false };

void worker_function()
{
	function&lt;void()&gt; task;

	while( true )
	{
		{
			unique_lock&lt;mutex&gt; lock( m );

			while( tasks.empty() &amp;&amp; !shutdown )
				cv.wait( lock );

			if( shutdown )
				return;

			task = move( tasks.front() );
			tasks.pop();
		}

		task();
		task = nullptr;
	}
}

// Ein simples Data-Objekt als Beispiel
struct objekt
{
	string 				   data; // Parameter
	std::future&lt;long long&gt; result; // Ergebnis
};

long long bsp_task( const shared_ptr&lt;objekt&gt;&amp; bsp_data )
{
	return stoll( bsp_data-&gt;data );
}

int main()
{
	thread worker{ worker_function };

	shared_ptr&lt;objekt&gt; shared_data{ make_shared&lt;objekt&gt;() };
	shared_data-&gt;data = &quot;42&quot;;

	auto ptask{ make_shared&lt;std::packaged_task&lt;long long()&gt;&gt;( bind( bsp_task , cref( shared_data ) ) ) };

	shared_data-&gt;result = ptask-&gt;get_future();

	{
		lock_guard&lt;mutex&gt; lock( m );
		tasks.emplace( [ptask] { ( *ptask )(); } );
	}

	cv.notify_one();

	// Hier ist der eigentliche Knackpunkt:
	// Ist der Aufruf von result.get() noch threadsafe, obwohl u.U. auf den data-Member zugegriffen wird (in anderen Beispielen evtl. auch schreibend)
	cout &lt;&lt; shared_data-&gt;result.get() &lt;&lt; endl;

	cin.get();

	{
		lock_guard&lt;mutex&gt; lock( m );
		shutdown = true;
	}
	cv.notify_one();
	worker.join();

	return 0;
}
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2489048</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2489048</guid><dc:creator><![CDATA[shft]]></dc:creator><pubDate>Mon, 29 Feb 2016 22:06:32 GMT</pubDate></item><item><title><![CDATA[Reply to std::future in Klasse noch Threadsafe? on Tue, 01 Mar 2016 11:03:32 GMT]]></title><description><![CDATA[<p>Ich hoffe ich habe dich jetzt richtig verstanden und versuche mich mal an einer Beantwortung.<br />
Der Aufruf von shared_data-&gt;result.get() ist sicher, da der Rückgabetyp long long kopiert wird.<br />
Bei einem Referenztyp als Shared State wäre die Sache kritischer.<br />
Generell:<br />
Sobald du auf shared_data-&gt;data schreibend in einem weiteren Thread zugreifst hast du einen data race.</p>
<p>Also:</p>
<pre><code>...
 cv.notify_one();
//der Workerthread greift lesend auf shared_data-&gt;data zu
//der Mainthread greift schreibend auf shared_data-&gt;data zu
// -&gt; Potentieller data race
shared_data-&gt;data = &quot;55&quot;;

cout &lt;&lt; shared_data-&gt;result.get() &lt;&lt; endl;
...
</code></pre>
<p>Wenn du wartest bis der WorkerThread fertig ist und dann auf shared_data-&gt;data schreibend zugreifst ist alles gut:</p>
<pre><code>...
cv.notify_one();

cout &lt;&lt; shared_data-&gt;result.get() &lt;&lt; endl;
//der Workerthread ist mit der Bearbeitung des Tasks fertig.
//der Mainthread kann sicher auf shared_data-&gt;data zugreifen.
shared_data-&gt;data = &quot;55&quot;;
...
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2489076</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2489076</guid><dc:creator><![CDATA[einwurf]]></dc:creator><pubDate>Tue, 01 Mar 2016 11:03:32 GMT</pubDate></item></channel></rss>