variadic template
-
Die gute alte Laufzeitpolymorphie ...
... also irgendwie so ...
class abstract_callable { public: virtual ~abstract_callable() {} virtual void run() = 0; ///< MUST only be called ONCE! }; template<int...> struct int_pack {}; template<class FunctorType, class TupleType, class Indices> class callable; template<class F, class...T, int...I> class callable<F,std::tuple<T...>,int_pack<I...>> : public abstract_callable { F fun; std::tuple<T...> params; public: template<class A, class...Args> explicit callable(A&& a, Args&&...args) : fun(std::forward<A>(a)) , params(std::forward<Args>(args)...) {} void run() { fun(std::forward<T>(std::get<I>(params))...); } }; template<class F, class...Args> std::unique_ptr<abstract_callable> make_callable(F&& fun, Args&&...args) { using std::forward; using std::unique_ptr; using std::make_tuple; typedef typename std::decay<F>::type fun_type; typedef decltype(make_tuple(forward<Args>(args)...)) tuple_type; typedef typename make_indices<sizeof...(Args)>::type indices_type; typedef callable<fun_type,tuple_type,indices_type> call_type; unique_ptr<abstract_callable> ac ( new call_type(forward<F>(fun),forward<Args>(args)...) ); return ac; } extern "C" void free_thread_func(void *user_data) { std::unique_ptr<abstract_callable> ac (static_cast<abstract_callable*>(user_data)); try { ac->run(); } catch (...) { // do something sensible here } }(ungetestet)
Da wo der Thread tatsächlich gestartet wird muss man natürlich den rohen Zeiger aus dem von make_callable zurückgegebenen unique_ptr per release befreien, damit das Objekt nicht schon wieder zerstört wird, bevor der Thread überhaupt zum Zuge kommt.
-
Sone schrieb:
Mach doch sowas in der Richtung:
... std::bind ...Wenn du std::bind dafür verwendest, ist es dir nicht Möglich Objekte von move-only Typen an einen Thread "per value" zu übergeben, da bind die gebundenen Parameter als Lvalue übergibt; denn man könnte den Funktor ja mehrmals ausführen und beim zweiten Mal soll es immer noch "funktionieren". std::thread fürht das Ding aber garantiert höchstens nur einmal aus. Es darf also gebundene Parameter als Rvalue übergeben.
-
und da ich den api-aufruf auch ganz gern im source-file hätte, fehlt mir schon der ansatz.

-
unskilled schrieb:
und da ich den api-aufruf auch ganz gern im source-file hätte, fehlt mir schon der ansatz.

Der API-Aufruf findet doch aber in einem Funktionstemplate statt? Und das kannste ja nicht in Source&Header aufteilen...
-
Zu CreateThread mal ein kleines Zitat aus der MSDN:
A thread in an executable that calls the C run-time library (CRT) should use the _beginthreadex and _endthreadex functions for thread management rather than CreateThread and ExitThread; this requires the use of the multithreaded version of the CRT. If a thread created using CreateThread calls the CRT, the CRT may terminate the process in low-memory conditions.
-
krümelkacker schrieb:
Sone schrieb:
Mach doch sowas in der Richtung:
... std::bind ...Wenn du std::bind dafür verwendest, ist es dir nicht Möglich Objekte von move-only Typen an einen Thread "per value" zu übergeben, da bind die gebundenen Parameter als Lvalue übergibt; denn man könnte den Funktor ja mehrmals ausführen und beim zweiten Mal soll es immer noch "funktionieren". std::thread fürht das Ding aber garantiert höchstens nur einmal aus. Es darf also gebundene Parameter als Rvalue übergeben.
Stimmt, fällt mir auf. Das hält seine Parameter in einem
std::tuple...
Wie wärs mit einem Gefrickel mitstd::reference_wrapper?
Edit: Nope. Temporäre Objekte können ja mitstd::reference_wrapper nicht gehalten werden, und sowieso...
-
Sone schrieb:
unskilled schrieb:
und da ich den api-aufruf auch ganz gern im source-file hätte, fehlt mir schon der ansatz.

Der API-Aufruf findet doch aber in einem Funktionstemplate statt? Und das kannste ja nicht in Source&Header aufteilen...
und weil ich denke, dass iwer nen vorschlag hat, wie es doch geht, habe ich hier gepostet...
-
unskilled schrieb:
und weil ich denke, dass iwer nen vorschlag hat, wie es doch geht, habe ich hier gepostet...
siehe meinen ersten Beitrag.
-
Warum baust du std::function nach, kk?
-
krümelkacker schrieb:
unskilled schrieb:
und weil ich denke, dass iwer nen vorschlag hat, wie es doch geht, habe ich hier gepostet...
siehe meinen ersten Beitrag.
ahhh - ganz übersehen. danke : >
bb
-
Kellerautomat schrieb:
Warum baust du std::function nach, kk?
Tue ich gar nicht. std::thread kannst du weder mit std::bind noch mit std::function implementieren -- jedenfalls nicht ohne größere Umwege. Der Standard verlangt, dass bei std::thread Rvalue-Parameter als solche weitergereicht werden.
Edit: Gut, man könnte std::function doch verwenden ... aber ich wüsste nicht, was das bringen sollte außer einer zusätzlichen Indirektion, auf die ich gern verzichten würde ...
-
[quote="Sone"]
template<typename Callable> DWORD WINAPI dummyFunc(LPVOID ptr) { (*reinterpret_cast<Callable*>(ptr))(); return 0; } struct thread { template<typename Callable, typename ... argTs> thread(Callable&& callable, argTs&&... args) { auto bound = std::bind(std::forward<Callable>(callable), std::forward<argTs>(args)...); auto ptr = dummyFunc<decltype(bound)>; mHandle = CreateThread(nullptr, 0, ptr, &bound, 0, nullptr);Oh, ich sehe gerade, dass du einen Zeiger auf ein automatisches Objekt übergibst. Das Objekt "bound" verschwindet doch aber gleich, wenn der Konstruktor fertig ist. 'Ne Freispeicherallozierung ist da schon praktischer.

-
Edit: Gleich kommt ne gefixte Version.
-
Der reinterpret_cast ist unnoetig.