MFC Dialog im laufenden Prozess beenden OHNE Multithreading
-
Hi ich nochmal.
Hab jetzt folgendes Problem im weiteren Verlauf. Das mit dem Multithreading hat sich nun dahingehend geklärt das ein Update der RTX erforderlich war um dies zu ermöglichen. Also alles gut.
Nun Starte ich einen Dialog, welcher einen Child-Dialog startet. In dem Child-Dialog starte ich einen Workerthread (obiger Code) in welchem ich allerdings auf Methoden des Parent-Dialogs zugreifen möchte.
ParentDlg* parDlg = (ParentDlg*)GetParent();
funktioniert zwar soweit, jedoch benötige ich den vorher in den Membervariablen enthaltenen Inhalt...
So wie ich das verstehe, erstelle ich eine neue Instanz des Parent-Dialogs, der keinen Bezug mehr auf den "original"-Dialog hat, und alle variablen "Quark" enthalten...
Hab dazu folgendes entdeckt, der auch das gleiche Problen hatte...allerdings Check ich es nicht ganz, wie hier das Problem gelöst werden kann.
http://www.c-plusplus.net/forum/74846
Bin für jede Hilfe dankbar
-
Und warum übergibst Du nicht einfach einen Zeiger auf das Parent?
Sobald Du irgend etwas machst, dass ein Window Handle in dem anderen Thread benutzt aus Deinem CDialog fliegt Dir die Funktion um die Ohren. Window Handles und Windows Objekte sind threadlokal.
Warum baust Du keine neutrale Struktur mit den Daten, die sowohl der Thread als auch der Dialog benutzt?
-
Und warum übergibst Du nicht einfach einen Zeiger auf das Parent?
Wie sähe das aus? Also ich rufe in dem Workerthread eine Memberfunktion des Parent auf. In dieser werden die Membervariablen selbiger verwendet, dort benötige ich aber den, vorher beim start des Programms, geladenen Inhalt.
Warum baust Du keine neutrale Struktur mit den Daten, die sowohl der Thread als auch der Dialog benutzt?
Mangelnde Erfahrung? Keine Ahnung wie sowas aussehen muss...bin noch relativ unerfahren. Wäre das dann so eine Art Globale Variablendeklaration??
-
AfxBeginThread (StartThread, param);
http://www.codeproject.com/Articles/2459/Using-AfxBeginThread-with-class-member-controlling
-
Ok, Danke erstmal...aber weiter bringt mich das auch nicht. Vorteile Gegenüber der Vorhergehenden Variante ergeben sich nicht, denn das was ich brauche funktionier immer noch nicht.
Also, ich zeig erstmal was ich jetzt Testweise gemacht habe.
Ein Dialog erstellt namens CTreadTestDlg.
void CTreadTestDlg::TestFunktion() { int Test = m_iAdrBits; m_iAdrBits++; } void CTreadTestDlg::OnButtonstartdlg() { // TODO: Add your control notification handler code here TestClassxD Testdlg; Testdlg.DoModal(); }
Diese Klasse beinhaltet die Memberfunktion Testfunktion(), in welcher auf die Membervariable m_iAdrBits zugegriffen wird.
Mit Klick auf den Button StartDlg wird ein ChildDialog erstellt, in welchem folgendes passiert:.h file:
static UINT StartThread (LPVOID param); //controlling function header typedef struct THREADSTRUCT //structure for passing to the controlling function { TestClassxD* _this; //this Objekt auf die Child Klasse CTreadTestDlg* ParentThread; //Objekt des ersten Dialogs } THREADSTRUCT;
.cpp file:
void TestClassxD::OnButtonstart() { cancelflag = 0; UpdateData(TRUE); THREADSTRUCT *_param = new THREADSTRUCT; _param->_this = this; AfxBeginThread (StartThread, _param); } void TestClassxD::OnButtonstop() { // TODO: Add your control notification handler code here cancelflag = 1; } UINT TestClassxD::StartThread (LPVOID param) { THREADSTRUCT* ts = (THREADSTRUCT*)param; //here is the time-consuming process which interacts with your dialog AfxMessageBox ("Thread is started!"); ts->_this->m_progressBar.SetRange (0, 1000); for (int i=0; i<(ts->_this->m_iCycles); i++) { if(!(ts->_this->cancelflag == 1)) { Sleep(5); ts->_this->m_progressBar.SetPos(i+1); ts->ParentThread->TestFunktion(); } } //you can also call AfxEndThread() here return 1; }
Und natürlich ist der Fehler immernoch vorhanden, dass wenn ich die Testfunktion des ersten Dialogs aufrufe, ein Access Violation Fehler kommt, weil er den Inhalt von m_iAdrBits nicht kennt...obwohl m_iAdrBits im OnInitDialog() des ersten Dialogs initialisiert und einen Wert erhalten hat.
Ist das was ich will überhaupt möglich? Oder versteht nur niemand was ich möchte?
PS: Das ist jetzt nur ein kleines Beispielprogramm, was ich in meine komplexere Anwendung integrieren muss/möchte...
PS2@Mods: Vielleicht wär es möglich den Titel zu ändern? Ich möchte nur kein neues Thema eröffnen, da es ja alles zusammen hängt...
Titelvorschlag: "aus Workerthread auf Membervariablen eines anderen Dialogs zugreifen" ...wenn das sachlich richtig ist
-
Du initialisierst in deinem Beispiel THREADSTRUCT::ParentThread nirgends, greifst aber in der Thread-Funktion darauf zu (ts->ParentThread->...).
Ich würde sagen poste mal 1:1 Code aus einem "funktionierenden" Beispiel, mit dem du das Problem nachstellen kannst.Code den man schnell für's Posten im Forum zurechtschnippelt oder gar "nachtippt" (ohne ihn ausprobiert zu haben) ist in solchen Fällen selten hilfreich.
Und natürlich darfst du nur aus dem Thread auf ein Fenster bzw. einen Dialog zugreifen, der dieses Fenster/diesen Dialog auch erzeugt hat.
D.h. du darfst aus dem Thread nicht auf ts->_this->m_progressBar zugreifen.Was OK wäre, wäre mit die entsprechende Message mit PostMessage() abzusetzen.
-
Hmm...danke, aber irgendwie kritisierst du immer das, was funktioniert
D.h. du darfst aus dem Thread nicht auf ts->_this->m_progressBar zugreifen
Warum?! Es funktioniert einwandfrei!
Du initialisierst in deinem Beispiel THREADSTRUCT::ParentThread nirgends, greifst aber in der Thread-Funktion darauf zu (ts->ParentThread->...).
typedef struct THREADSTRUCT //structure for passing to the controlling function { TestClassxD* _this; //this Objekt auf die Child Klasse CTreadTestDlg* ParentThread; //Objekt des ersten Dialogs } THREADSTRUCT
soviel dazu...
Und natürlich darfst du nur aus dem Thread auf ein Fenster bzw. einen Dialog zugreifen, der dieses Fenster/diesen Dialog auch erzeugt hat.
OK! Zumindest hast du das Problem vor dem ich stehe erkannt. Ich versuche ja auch nicht auf Fenster/Controls/Dialog zuzugreifen, sondern auf eine Membervariable der Dialogklasse.
Ich möchte eigentlich nur wissen, ob das wirklich so ein Ding der unmöglichkeit ist. Der Luxus einen weiteren Dialog zu öffnen in welchem man einen Langzeittest starten kann ist einfang sehr Angenehm. Wenn mir aber keine Lösung einfällt/präsentiert wird, werde ich wohl die wenigen Controls aus dem Child-Dialog in den "großen" Parent Dialog implementieren, und diese per Menü einfach Disablen/Enablen...
Nicht Schön, aber wird sich im zuge von Multithreading wohl nicht ändern lassen oder?
Was mich aber immernoch Interessiert, ist Martin Richters vorschlag zur neutralen Struktur
wtf is das? Wie kann ich mir so etwas vorstellen? Kein Plan wie man so etwas angeht.
-
Alter Freund der schwedischen Blasmusik, ...
KPY3EP schrieb:
Hmm...danke, aber irgendwie kritisierst du immer das, was funktioniert
Blubb
D.h. du darfst aus dem Thread nicht auf ts->_this->m_progressBar zugreifen
Warum?! Es funktioniert einwandfrei!
Weil m_progressBar ein CONTROL aka. FENSTER ist. Das darfst du nur aus dem Thread verwenden der es erzeugt hat. OK, unter bestimmten Voraussetzungen funktioniert das auch "gut" über Thread-Grenzen hinweg, man kann sich aber ganz leicht damit rückwärts durchs Knie schiessen.
Du initialisierst in deinem Beispiel THREADSTRUCT::ParentThread nirgends, greifst aber in der Thread-Funktion darauf zu (ts->ParentThread->...).
typedef struct THREADSTRUCT //structure for passing to the controlling function { TestClassxD* _this; //this Objekt auf die Child Klasse CTreadTestDlg* ParentThread; //Objekt des ersten Dialogs } THREADSTRUCT
soviel dazu...
Ist dir die Bedeutung des Wortes "initialisieren" bekannt?
Ja? Glaub ich nichtvoid TestClassxD::OnButtonstart() { cancelflag = 0; UpdateData(TRUE); THREADSTRUCT *_param = new THREADSTRUCT; _param->_this = this; // HIER FEHLT EIN _param->ParentThread = irgendwas; AfxBeginThread (StartThread, _param); }
Soviel dazu.
-
Ich glaub du verstehst imemr noch nicht, was ich will...lies dir bitte nochmal meinen Letzten Post unterster Absatz durch.
Weil m_progressBar ein CONTROL aka. FENSTER ist. Das darfst du nur aus dem Thread verwenden der es erzeugt hat. OK, unter bestimmten Voraussetzungen funktioniert das auch "gut" über Thread-Grenzen hinweg, man kann sich aber ganz leicht damit rückwärts durchs Knie schiessen.
Was ne Begründung...
Und warum machen das alle so? Selbst in dem Beispiel welches hier verlinkt wurde wird es so gemacht.OK! Zumindest hast du das Problem vor dem ich stehe erkannt.
Diese Aussage nehme ich zurück. Ich versuch nochmals zu erklären worum es geht.
vielleicht hilft ASCII-Art
____________________ ______________________ | Dialog | | Dialog | ___________________ | 1 | => | 2 | => | Workerthread |---. -------------------- ---------------------- ------------------- | ^ ^ | | | | ---------------------------------------------------------------------
zugriff vom Workerthread auf Membervariablen /Methoden der Dialogklassen...
Das funktioniert bisher nur für Dialog 2. beim Zugriff auf Dialog 1 kommt Error.
Ich bin zwar sowieso schon damit fertig, und hab es anders gelöst, jedoch interessiert mich ob bzw. was hier die schwierigkeit darstellt...
-
Also ganz langsam zum mitschreiben.
Du hast da eine Zeile
ts->ParentThread->TestFunktion();
in deinem Programm.
ts ist die "THREADSTRUCT" die du mit folgender Funktion zusammenbaustvoid TestClassxD::OnButtonstart() { cancelflag = 0; UpdateData(TRUE); THREADSTRUCT *_param = new THREADSTRUCT; _param->_this = this; AfxBeginThread (StartThread, _param); }
Da wird die Membervariable "ParentThread" bloss leider nie geschrieben. D.h. da steht ne Hausnummer drin.
D.h. du greifst nicht auf den "Dialog 1" zu, sondern einfach irgendwo in den Speicher. Und deswegen schnalzt es dort.Wenn du nicht unglaublich schwer von Begriff bist, müsstest du das eigentlich verstehen.
KPY3EP schrieb:
Ich glaub du verstehst imemr noch nicht, was ich will...lies dir bitte nochmal meinen Letzten Post unterster Absatz durch.
Und ich glaube du hast einfach keine Ahnung von Programmieren.
Weil m_progressBar ein CONTROL aka. FENSTER ist. Das darfst du nur aus dem Thread verwenden der es erzeugt hat. OK, unter bestimmten Voraussetzungen funktioniert das auch "gut" über Thread-Grenzen hinweg, man kann sich aber ganz leicht damit rückwärts durchs Knie schiessen.
Was ne Begründung...
Und warum machen das alle so? Selbst in dem Beispiel welches hier verlinkt wurde wird es so gemacht.Was kann ich dafür dass Heerscharen von Programmierern keinen Tau von Multithreading haben?
Das m_progressBar.SetPos() ist für sich genommen noch kein Problem.
Problematisch wird es meistens dann, wenn die Leute versuchen den Thread im OnOK/OnClose des "parent" Dialogs zu beenden.Ich bin zwar sowieso schon damit fertig, und hab es anders gelöst, jedoch interessiert mich ob bzw. was hier die schwierigkeit darstellt...
Dann solltest du vielleicht lesen was ich dir schreiben, anstatt immer nur zu behaupten dass ich dein Problem nicht verstanden habe.
So ein Dialog der nen Worker-Thread rausstartet ist genau überhaupt kein Problem, das hat man in ein paar Minuten runterprogrammiert.