Pointer innerhalb Klasse auf Memberfunktion
-
Tut mir wirklich leid, aber ich verstehe zwar was du meinst, weiß aber nicht wie genau ich das umsetzen soll.
Was genau soll ich, deiner Meinung nach, denn als void (__stdcall)(void*) - also ersten Parameter - übergeben?
&((HClasses::ServerSocket*)_instance)->_acceptWenn ich es caste bekomme ich immer noch die Fehlermeldung:
Ungültige Operation auf Ausdruck einer gebundenen Memberfunktion_instance ist ein void*
-
Was genau verstehst Du denn nicht an dem 3. Beitrag dieses Threads?
-
Naja, hab ich doch geschrieben. Ich weiß nicht wie ich die Thread-Funktion übergeben soll.
-
Ich habe doch ein Beispiel dabei gehabt, was die Übergabe zeigt.
-
Sebastian Pizer schrieb:
Ich habe doch ein Beispiel dabei gehabt, was die Übergabe zeigt.
Wenn du das hier meinst:
extern "C" { void __stdcall transmogrify(void* context) { static_cast<MeineKlasse*>(context)->elementfunktion(); } } ... MeineKlasse* p = ...; Threading::HTread t (&transmogrify, p, ...);Das Problem ist aber, dass ich nicht weiß wo ich transmogrify deklarieren soll? Innerhalb der Klasse? Da bekomme ich einen Compilerfehler. Tut mir leid, wenn ich mich gerade etwas doof anstelle.
-
Wenn ich mir anschaue, wie es in boost::thread gemacht wird:
struct ThreadProxyData { typedef unsigned (__stdcall* func)(void*); func start_address_; void* arglist_; ThreadProxyData(func start_address,void* arglist) : start_address_(start_address), arglist_(arglist) {} }; DWORD WINAPI ThreadProxy(LPVOID args) { ThreadProxyData* data=reinterpret_cast<ThreadProxyData*>(args); DWORD ret=data->start_address_(data->arglist_); delete data; return ret; } typedef void* uintptr_t; inline uintptr_t const _beginthreadex(void* security, unsigned stack_size, unsigned (__stdcall* start_address)(void*), void* arglist, unsigned initflag, unsigned* thrdaddr) { DWORD threadID; HANDLE hthread=CreateThread(static_cast<LPSECURITY_ATTRIBUTES>(security),stack_size,ThreadProxy, new ThreadProxyData(start_address,arglist),initflag,&threadID); if (hthread!=0) *thrdaddr=threadID; return reinterpret_cast<uintptr_t const>(hthread); }Stelle ich fest, dass hier doch nicht viel anders verfahren wird.
-
FrEEzE2046 schrieb:
Wenn du das hier meinst:
extern "C" { void __stdcall transmogrify(void* context) { static_cast<MeineKlasse*>(context)->elementfunktion(); } } ... MeineKlasse* p = ...; Threading::HTread t (&transmogrify, p, ...);Das Problem ist aber, dass ich nicht weiß wo ich transmogrify deklarieren soll? Innerhalb der Klasse?
Nein, das soll eine freie Funktion sein. Ich bin mir nur nicht sicher, ob die "__stdcall"-Syntax da richtig ist. Das ist eh kein Standard-C++...
Idealerweise versteckt man so etwas hinter der Thread-Bibliothek, wie es boost::thread tut. boost::thread akzeptiert beliebige "Funktoren" und setzt das intern wahrscheinlich mit "Type Erasure" um. Du hast aber nicht vor, eine eigene Thread-Bibliothek zu schreiben, oder? Das würde ich Spezialisten überlassen...
Gruß,
SP
-
nein natürlich nicht.
Ich halte die Vorgehensweise dennoch für schlauer, dass man auch normale Funktionen übergeben kann, die dann intern aufgerufen werden. Das macht alles ein wenig einfacher.
Ich bekomme jedoch bei der Zuweisung von "ret" eine Exception
unsigned long __stdcall ThreadProxy( void* args ) { ThreadProxyData* data = reinterpret_cast<ThreadProxyData*>(args); DWORD ret = data->start_address_(data->arglist_); delete data; return ret; }
-

Funktionen "castet" man nicht.Ich übergebe an den nächsten Hilfsbereiten. Meine Zeit für heute ist um.
-
Sebastian Pizer schrieb:

Funktionen "castet" man nicht.Ich meinte auch nicht die Funktion die gecastet wird. Hier wird doch einfach eine struct gecastet, die dann die Adresse der Funktion und deren Parameter enthält oder etwa nicht?
-
Hier ist ein letztes und vollständiges Beispiel, welches das Prinzip verdeutlichen soll, mit dem man Elementfunktionen aufrufen kann, obwohl man einen Zeiger auf eine freie Funktion übergeben muss. Der Schlüssel zur Lösung ist hier der void*-Parameter.
#include <iostream> typedef void thread_funktion_t(void*); void ruf_auf(thread_funktion_t* pf, void* kontext) { pf(kontext); } class MeineKlasse { public: void foo(); }; void MeineKlasse::foo() { std::cout << "Hallo!\n"; } void proxy_MeineKlasse_foo(void* kontext) { static_cast<MeineKlasse*>(kontext)->foo(); } int main() { MeineKlasse o; ruf_auf(proxy_MeineKlasse_foo,&o); }Wenn Du damit jetzt nichts anfangen kannst, solltest Du die Finger von Threads lassen.
-
Sebastian Pizer schrieb:
Wenn Du damit jetzt nichts anfangen kannst, solltest Du die Finger von Threads lassen.
Doch doch, dass ist mir doch auch klar. Die Frage geht eigentlich in eine andere Richtung mittlerweile.
Wie kann ich es anstellen, dass ich meiner Thread Klasse eine Funktion mit beliebiger Konvention übergebe, so wie es ja anscheinend boost::thread macht?
Ich meine, dass bekomme ich natürlich schon hin:typedef unsigned (__stdcall *func)(void*); func f = static_cast<func>(this->_lpFunction); this->_hThread = mybeginthreadex( NULL, 0, f, this->_lpParams, CREATE_SUSPENDED, 0 );aber wenn _lpFunction ein void* ist, wird logischerweise der Stack nicht korrekt bereinigt. Mich würde interessieren, wie man diese Problematik lösen kann.
-
FrEEzE2046 schrieb:
Die Frage geht eigentlich in eine andere Richtung mittlerweile.
Wie kann ich es anstellen, dass ich meiner Thread Klasse eine Funktion mit beliebiger Konvention übergebe, so wie es ja anscheinend boost::thread macht?
Mit einer Kombination aus Templates und Laufzeitpolymorphie. Die Technik heißt dann "Type Erasure".
-
Sebastian Pizer schrieb:
Mit einer Kombination aus Templates und Laufzeitpolymorphie. Die Technik heißt dann "Type Erasure".
Da lohnt sich der Aufwand nicht wirklich, würde ich sagen.
Ein Problem hat deine Lösung jedoch noch:
1. Die Thread-Funktion selbst startet die eigentlich Funktion die durch den Thread ausgeführt werden soll und muss außerhalb der Klasse deklariert sein.
2. Damit muss die eigentliche Thread-Funktion (innerhalb der Klasse) unbedingt public sein, damit ich sie aufrufen kann ...nicht unbedingt die eleganteste Lösung
-
FrEEzE2046 schrieb:
Ein Problem hat deine Lösung jedoch noch:
1. Die Thread-Funktion selbst startet die eigentlich Funktion die durch den Thread ausgeführt werden soll und muss außerhalb der Klasse deklariert sein.
2. Damit muss die eigentliche Thread-Funktion (innerhalb der Klasse) unbedingt public sein, damit ich sie aufrufen kann ...Es war keine "Lösung" sondern ein Beispiel, welches Dir etwas verdeutlichen sollte.
nicht unbedingt die eleganteste Lösung

-
Sebastian Pizer schrieb:
FrEEzE2046 schrieb:
Ein Problem hat deine Lösung jedoch noch:
1. Die Thread-Funktion selbst startet die eigentlich Funktion die durch den Thread ausgeführt werden soll und muss außerhalb der Klasse deklariert sein.
2. Damit muss die eigentliche Thread-Funktion (innerhalb der Klasse) unbedingt public sein, damit ich sie aufrufen kann ...Es war keine "Lösung" sondern ein Beispiel, welches Dir etwas verdeutlichen sollte.
nicht unbedingt die eleganteste Lösung

Ja, okay - aber soll das etwa heißen, dass es keine Lösung für das Problem gibt? Es wird doch wohl möglich sein einen Thread aus einer Klasse heraus zu starten
-
Nichts hindert dich, eine statische Memberfunktion zu verwenden.
-
FrEEzE2046 schrieb:
Ja, okay - aber soll das etwa heißen, dass es keine Lösung für das Problem gibt?
Welches Problem? Gibt es noch eins?
FrEEzE2046 schrieb:
Es wird doch wohl möglich sein einen Thread aus einer Klasse heraus zu starten
Falls Du damit meinst, einen Thread eine Elementfunktion ausführen zu lassen: Klar, das geht! Siehe boost::thread, boost::bind und als "type erasure"-Beispiel noch boost::function. Ich werde Dir das hier nicht vorkauen. Du hast genug Stichwörter bekommen. Recherchiere selbst. Es lohnt sich!
Gruß,
SP
-
Ich werde es mir anschauen. Ich habe es auf die schnelle erst ein mal so gelöst:
template< typename THREAD_ROUTINE > struct ThreadProxyData { THREAD_ROUTINE lpFunction; THREAD_DATA lpParams; ThreadProxyData( THREAD_ROUTINE start_address, THREAD_DATA arglist) : lpFunction(start_address), lpParams(arglist) {} };Diese struct wird jetzt dem Konstruktor übergeben. Insofern ist dort bereits festgelegt, wie die Funktion aussieht. Intern rufe ich dann eine andere Funktion des Typs unsigend (__stdcall *Func)(void*) auf, welche wiederum dann diese Funktion aufruft.
Ist eine - denke ich - ganz gute Lösung.
-
Wie ich nun einen Zeiger auf eine Klassenmethode bekomme hat sich dadurch natürlich immer noch nicht geklärt. Ich löse das jetzt wie folgt:
// Funktion außerhalb Klasse unsigned int __stdcall __callAccept(void* _instance) { while( TRUE ) { static_cast<HClasses::ServerSocket*>(_instance)->_accept( NULL ); } return 0; } // innerhalb Klasse this->_acceptThread = new Threading::HThread( __callAccept, this, HClasses::Threading::PREPARED, false );Naja, eine wenig schöne Lösung. Fällt jemandem eine elegantere Art ein?