Problem mit Methode einer Klasse als Threadfunktion
-
Hallo,
ich möchte in einem Thread die Methode einer Klasse aufrufen. Dazu habe ich in der Klasse extra einen Wrapper deklariert, der dann meine gewünschte Funktion aufruft. Wenn ich in dieser Funktion aber auf Members der Klasse zugreife, kommt es immer zum Programmabsturz. Wenn ich das Programm debugge und in der Funktion Run (also Zeile 20 lande), dann steht im Debug-Fenster für die Variable m_iVal "CXX0030: Fehler: Ausdruck kann nicht ausgewertet werden".
Könnte mir bitte jemand erklären, woran das liegt und was ich machen muss, um das Problem zu beseitigen? Im Anhang ein Beispielprogramm, wo soeben genanntest Problem auftritt:HANDLE hMutex; class cClass { public: cClass::cClass() : m_iVal(0) {} static void ThreadRun(LPVOID who) { static_cast<cClass*>(who)->Run(); } void Run (); private: int m_iVal; }; void cClass::Run () { if(!m_iVal) // Diese Zeile hier scheint zum Absturz zu führen! { for (int i=0;i<75;i++) { std::cout << i << " Run" << std::endl; } } } int main() { cClass cTest; HANDLE hThrds[1]; DWORD aThreadID[1]; hMutex = CreateMutex(NULL,FALSE,NULL); hThrds[0] = (HANDLE) _beginthreadex(0,0, (unsigned (_stdcall *)(void *)) cTest.ThreadRun, NULL,0, (unsigned *) &aThreadID[0]); WaitForMultipleObjects(1, hThrds, TRUE, INFINITE); CloseHandle(hThrds[0]); return(0); }Vielen Dank!
V.K.
-
vlt solltest du statt NULL &cTest uebergeben?

(unsigned (_stdcall *)(void *)) cTest.ThreadRun <-- damit schiesst du dir auch garantiert in den fuss,wenn du an der stelle casten musst hast du ehr in der deklaration was falsch gemacht.
ueberhaupt klappt es nicht da ne statische methode zu nehmen,das sollte so aussehen:
namespace { extern "C" unsigned Class_Run(void* p) { static_cast<cClass*>(p)->Run(); return 0; } }dann kannst du &Class_Run,&cTest an der geeigneten stelle uebergeben. mindestens comeau frisst das sonst nicht.
PS: ungarische notation war (vor)gestern...
-
Hi t001,
vielen Dank für deine Hilfe. Ich habe jetzt dein Vorschlag wie folgt umgesetzt, so dass es zu keinen Abstürzen mehr kommt:
HANDLE hMutex; class cClass { public: cClass::cClass() : m_iVal(0) {} void Run (); private: int m_iVal; }; namespace { extern "C" unsigned Class_Run(void* p) { static_cast <cClass*> (p)->Run(); return 0; } } void cClass::Run () { if(!m_iVal) { for (int i=0;i<75;i++) { std::cout << i << " Run" << std::endl; } } } int main() { cClass cTest; HANDLE hThrds[1]; DWORD aThreadID[1]; hMutex = CreateMutex(NULL,FALSE,NULL); hThrds[0] = (HANDLE) _beginthreadex(0,0, (unsigned (_stdcall *)(void *)) &Class_Run,&cTest,0,(unsigned *) &aThreadID[0]); WaitForMultipleObjects(1, hThrds, TRUE, INFINITE); CloseHandle(hThrds[0]); return(0); }Dazu hätte ich aber noch ein paar Fragen.
1.) Das casten bei _beginthreadex wie folgt "(unsigned (_stdcall *)(void *)) &Class_Run" konnte ich nicht anders umsetzen. Ich habe es probiert an anderer Stelle unterzubringen, aber leider hat der Compiler das nicht mitgemacht.
2.) Habe ich es richtig verstanden, dass das namespace außerhalb der Klasse aufgeführt werden muß?
3.) Kann man das ganz noch eleganter machen, in dem man z.B. eine Thread-Klasse definiert und die Klasse cClass dann von dieser ableitet und die run-Funktion dann virtual deklariert? Sowas habe ich auch schonmal irgendwo gesehen.
4.) Wieso benutzt man keine ungarische Notation mehr? Was gibt es da Neueres?Vielen Dank!!
V.K.
-
schau dir mal das ActiveObject Pattern an.. das ist genau das was du suchst;)
-
VerbalKint schrieb:
4.) Wieso benutzt man keine ungarische Notation mehr? Was gibt es da Neueres?
Jein. UN ist durchaus in den ein oder anderen Projekt noch in Verwendung, aber am aussterben. Statt dessen verwendet man sinnvolle IDEs die den Typ eh anzeigen, sprechende Bezeichner...
Kurze Gründe gegen UN:
a) Weitere Sprache zu lernen (und Lesbarkeit leidet)
b) In jeder Sprache in der man eigene Typen definieren kann nimmt es überhand
c) Spätestens mit Templates ist eh die UN unmöglich einzusetzencu André
-
VerbalKint schrieb:
1.) Das casten bei _beginthreadex wie folgt "(unsigned (_stdcall *)(void *)) &Class_Run" konnte ich nicht anders umsetzen. Ich habe es probiert an anderer Stelle unterzubringen, aber leider hat der Compiler das nicht mitgemacht.
Der cast sollte gar nicht mehr noetig sein,was passiert denn,wenn du ihn in der letzten version einfach rausnimmst, &Class_Run sollte den richtigen typ haben.
2.) Habe ich es richtig verstanden, dass das namespace außerhalb der Klasse aufgeführt werden muß?
joah, das sagt in dem fall das die elemente darin nicht aus der datei exportiert werden, weils nur hilfsfunktionen sind.
3.) Kann man das ganz noch eleganter machen, in dem man z.B. eine Thread-Klasse definiert und die Klasse cClass dann von dieser ableitet und die run-Funktion dann virtual deklariert? Sowas habe ich auch schonmal irgendwo gesehen.
Klar kann man das,hast du ja schon fast gemacht. der unterbau zur C API wird allerdings nie huebscher. vlt willst du auch boost.threads verwenden.