_beginthread - missing argument list
-
Hallo zusammen,
in meiner Anwendung gibt es eine Menge Threads. Die Thread_Funktionen (void cdecl ...) sind in einer Klasse, genauso wie die Funktion start_system(), mit der man mit _beginthread die Threads startet.
Also (vereinfachtes Beispiel):
class sys { void cdecl ThreadA(void* pParam) { //was auch immer... } void start_system(void *uParam[14]) { hThread[0] = _beginthread(ThreadA, 0, uParam[0]); } };Hier bekomme ich jetzt die Fehlermeldung:
error C3867: 'sys::ThreadA': function call missing argument list; use '&sys::ThreadA' to create a pointer to member
Das hat mich jetzt aber noch nicht aus dem Konzept gebracht. Google is your friend, also habe ich diese Seite gefunden:
http://www.daniweb.com/forums/thread186223.html#
Demzufolge muss ich die Funktionen als static deklarieren. Dann muss ich aber auch alle Member, auf die zugegriffen wird, als static deklarieren. Das hießt dann ja wohl, dass diese Member für alle Objekte gleich sind, was genau das ist, was ich nicht möchte
.
Ich möchte nämlich mehrere Objekte der Klasse sys erstellen können, um sie für Multi-User zu benutzen. Gibt es da noch einen anderen Weg?
Ich habe auch schon darüber nachgedacht, die Thread-Funktionen auszulagern. Dann bräuchte ich aber einen zusätzlichen Pointer in der Thread-Funktion, die angibt, welches sys-Objekt denn jetzt gerade aufruft... und das geht ja wohl nicht (soweit ich weiß, sind die Schnittstellen für Thread-Funktionen standartisiert?).
Also, ich stecke in einer Zwickmühle. Seht ihr da einen Ausweg?Schon Mal im Voraus, Vielen Dank für Eure Antworten!
Gruß,
LauritzG
-
Ich glaube üblicherweise wird das so gelöst, dass man die eigentliche Thread-Funktion als freie oder static Funktion implementiert, ihr aber in der arglist den this-Zeiger übergibt. Natürlich muss dann u.a. sichergestellt sein, dass das Objekt wärend der gesamten Laufzeit des Threads existent bleibt.
Edit: Eventuell solltest du dir auch mal boost.thread ansehen, damit ist es auch möglich, Threads mit Instanzmethoden zu starten.
-
Den einen Teil sagt dir ja der Compiler (&sys::ThreadA statt nur ThreadA), den anderen Teil kann man sich denken:
class sys { struct ThreadParams { sys* that; void* param; }; void ThreadA(void* pParam) { //was auch immer... } static void ThreadATrampoline(void* pParam) { std::auto_ptr<ThreadParams> p(static_cast<ThreadParams*>(pParam)); p->that->ThreadA(p->param); } void start_system(void **uParam) { std::auto_ptr<ThreadParams> p(new ThreadParams); p->that = this; p->param = uParam[0]; hThread[0] = _beginthread(&sys::ThreadATrampoline, 0, p.get()); if (hThread[0] != 0) p.release(); // ownership wurde erfolgreich an den thread übergeben } };Und verwende immer _beginthreadex wenn du mit dem Thread-Handle irgendwas anfangen willst (ausser direkt nach _beginthread zu checken ob's funktioniert hat).
-
Vielen Dank für eure Antworten!
Ich werde mir das alles morgen noch einmal genauer ansehen; ich denke, damit müsste mein Problem gelöst sein.Vielen, Vielen Dank!
Ich schreibe noch mal, wenn ich meinen Code umgeschrieben habe.Danke!
LauritzG

-
So, habe jetzt meinen Code umgeschrieben - alles funktioniert.
Ich habe beistd::auto_ptr<ThreadParams> p(new ThreadParams);das
(new ThreadParams)weggelassen, wenn es irgendwelche Probleme geben sollte, sehe ich, ob ich das da wieder drankriege.
Vielen, Vielen Dank euch beiden !!!

Danke!
Gruß,
LauritzG
-
LauritzG schrieb:
So, habe jetzt meinen Code umgeschrieben - alles funktioniert.
Ich habe beistd::auto_ptr<ThreadParams> p(new ThreadParams);das
(new ThreadParams)weggelassen, wenn es irgendwelche Probleme geben sollte, sehe ich, ob ich das da wieder drankriege.
WTF?
Natürlich brauchst du das.
-
hustbaer schrieb:
LauritzG schrieb:
So, habe jetzt meinen Code umgeschrieben - alles funktioniert.
Ich habe beistd::auto_ptr<ThreadParams> p(new ThreadParams);das
(new ThreadParams)weggelassen, wenn es irgendwelche Probleme geben sollte, sehe ich, ob ich das da wieder drankriege.
WTF?
Natürlich brauchst du das.
Gut, dann werde ich das mal wieder dranbauen. Meine momentane Lösung sieht nämlich so aus:class sys { struct ThreadParams { sys* that; void* param; }; void ThreadA(void* pParam) { //was auch immer... } static void ThreadATrampoline(void* pParam) { std::auto_ptr<ThreadParams> p(static_cast<ThreadParams*>(pParam)); p->that->ThreadA(p->param); } void ThreadB(void* pParam) { //was auch immer... } static void ThreadBTrampoline(void* pParam) { std::auto_ptr<ThreadParams> p(static_cast<ThreadParams*>(pParam)); p->that->ThreadB(p->param); } void start_system(void **uParam) { std::auto_ptr<ThreadParams> p[2]; // Hier ist jetzt ein Array for(int i = 0; i< 2; i++) { p[0]->that = this; p->param = uParam[0]; } hThread[0] = _beginthread(&sys::ThreadATrampoline, 0, p[0].get()); if (hThread[0] != 0) p[0].release(); hThread[1] = _beginthread(&sys::ThreadATrampoline, 0, p[1].get()); if (hThread[1] != 0) // hier ist jetzt alles auf Array umgebaut [b]p[1].release(); } };Wenn ich das new ThreadParams drangelassen hatte, hat der Compiler immer rumgemeckert, dass ich das Ganze so : {... , ...} initialisieren soll. Als ich das dann probiert habe (mit 15 Threads) gab es nur noch mehr Fehler.
(ich gebs zu, ich habe keine Ahnung von dynamischem Allokieren, Speicherverwaltung, STL usw.
und mache meine Programme eigentlich haupsächlich ohne sowas). Ich werd mich nochmal dransetzen, vielleicht funktioniert ja eine Initialisierung wie://start_system(){... for(int i = 0; i <2; i++) p[i] = new ThreadParams();Auf jeden Fall vielen Dank schon Mal (und ich werde mal lernen müssen, mit STL umzugehen
).
Gruß
LauritzG
-
Mach doch bitte eine Funktion die dir genau einen Thread startet, und ruf diese dann 2x auf. Dann musst du auch nicht alles wiederholen und auch nicht in der Thread-Starte-Funktion mit Arrays rumhantieren.
Und verwende bitte _beginthreadex, _beginthread ist eigentlich immer ein Fehler wenn man mit den Thread-Handles danach noch was anfangen will.
Was die ThreadParams Struktur angeht: du kannst der auch gerne einen Konstruktor verpassen, dann kannst du die mit
new ThreadParams(this, uParam)initialisieren.Oder steig auf eine Threading-Library um, so dass du dich um den ganzen Ranz nichtmehr selbst kümmern musst.
-
Vielen Dank für deine Antwort!
Ich habe jetzt eine Start-Funktion für die Threads gemacht, das sieht jetzt in etwa so aus:int start_thread(int index, void* thread_f, void **uParam) { std::auto_ptr<thread_data> p(new thread_data); p->self = this; p->param = uParam[index]; return _beginthread(thread_f, 0, uParam[index]); }Das einzige Problem ist, dass mir der Compiler sagt, dass:
error C2664: '_beginthread' : cannot convert parameter 1 from 'void *' to 'void (__cdecl *)(void *)' 1829
Jetzt habe ich versucht, dieses
void* thread_f
auszutauschen gegen void* _cdecl thread_f und noch ein paar andere, nur es funktionierte nicht
Hat jemand da noch eine Idee?
Ach so: Ich habe jetzt auf _beginthreadex verzichtet, da ich eh die meisten Parameter mit NULL besetzen würde und ich mit den Handles eigentlich auch nichts mehr anfangen will. Beenden der Threads läuft über eine bool-Variable, die die Threads prüfen; wenn sie true ist, beendet sich der Thread.Vielen Dank schon Mal im Voraus
und ein schönes Wochenende sowie ein guter 1. Mai
wünscht
LauritzG