AfxMessageBox in Workerthreads
-
Hallo,
wie allgemein bekannt ist, sind jegliche GUI Manipulationen in Workerthreads strengstens untersagt.
Allerdings komme ich in die Situation wo dies erforderlich ist. Ich muß einmal eine AfxMessageBox in einem WT anzeigen lassen. Dies ist notwendig für den Fall wenn der Behälter, in welchem zu bearbeitende Werkstücke drin sind, leer ist. Der Benutzer muss darauf hingewiesen werden um diesen Behälter wieder zu füllen bevor der Prozess weiter gehen kann.
Ferner soll die AMB eh jegliche GUI Interaktionen (auch die des Mainthreads) verhindern.
Ansonsten läuft der WT ohne GUI Manipulation (außer PostMessage ans MainGUI) ab.Wenn ich nun in den WT eine AMB einbaue verhält sich das Programm auch wie gewünscht. Auch Rückgabewerte (OK, CANCEL) bekomme ich korrekt.
Fragen:
1. Warum funktioniert das in meinem Fall obwohl auch von AMBs in WTs tunlichst abgeraten wird?2. Welche Risiken würde ich eingehen wenn ich diese Methode behalte anstatt es "sauber" mit PostMessage an MainGUI mit WaitForSingleObject/SetEvent zu implementieren?
-
Scheinbar bauen wir ähnliche Maschinen
wie allgemein bekannt ist, sind jegliche GUI Manipulationen in Workerthreads strengstens untersagt.
Das ist ein wenig hart ausgedrückt. Es wird aus gutem Grund nicht empfohlen.
Allerdings komme ich in die Situation wo dies erforderlich ist. Ich muß einmal eine AfxMessageBox in einem WT anzeigen lassen.
Nein, in diese Situation kommst Du nicht!
Dies ist notwendig für den Fall wenn der Behälter, in welchem zu bearbeitende Werkstücke drin sind, leer ist. Der Benutzer muss darauf hingewiesen werden um diesen Behälter wieder zu füllen bevor der Prozess weiter gehen kann.
Ferner soll die AMB eh jegliche GUI Interaktionen (auch die des Mainthreads) verhindern.Das ist auch nicht ganz korrekt!
Richtig ist doch eher:
1. Der Prozess darf nicht starten wenn der Stückbehälter leer ist
2. Der Prozess muss stoppen wenn der Stückbehälter leer wird.
3. Der Prozess muss stoppen wenn der Operator den Stop Button drückt.In den Fällen 1. und 2. muss der Operator angewiesen werden den Stückbehälter zu füllen.
Das bedeutet aber, dass die Anzeige im Fall 1. ja auf jeden Fall im UI-Thread läuft. Da ist es doch ein Klacks diese Anzeige auch aus dem Thread mit PostMessage auszulösen.
Ich habe das so gelöst:
Ein Thread und 3 Events ("Start", "Stop" und "StopThread").
Im Thread wird auf die Events "Start" und "StopThread gewartet.
"Start" gesetzt -> verzweigt in den Process Loop.
"StopThread" gesetzt -> beendet den Thread.Im Prozess Loop wird nach der Bearbeitung eines Werkstücks geprüft ob noch weitere Werkstücke vorhanden sind.
- Keine weiteren Werkstücke -> PostMessage (IDS_EMPTY_CONTAINER) -> return zum Thread.
- "Stop" gesetzt -> Return zum Thread
Der Thread wartet nun wieder auf die Events "Start" und "StopThread"
Das ist doch so simpel, dass sich irgendwelche Tricks gar nicht lohnen.
-
Moin,
also doch besser die Set/Wait Methode. Gut, sollte kein Problem sein.
Ich habe zwischenzeitlich auch Debugfehler bekommen, die nicht nachvollziehbar waren weil diese nicht reproduzierbar auftraten. Das ist dann wohl der Grund warum in WTs keine UI Ops empfohlen sind.Danke!
-
Sende doch dem GUI-Thread einfach eine Nachricht, dass er eine MessageBox öffnen soll.
Du Workerthreads die Arbeit verrichten ( wie auch immer die aussieht ) und einen GUI-Thread, der evtl. Ergebnisse sichtbar macht. Und beides muss sauber getrennt sein.
-
Moin,
ich habe nun neben dem MainGUIThread auch noch 2 Workerthreads innerhalb eines Prozesses.
WT 1 = Thread für Werkstückbeförderung aus Behälter zur Abholstelle
WT 2 = Thread für WerkstückbearbeitungDa der Arbeitsraum mittels Lichtvorhang geschützt ist, kann ich nicht einfach in WT1 diesen wegen Behälterfüllung abschalten während WT2 weiter die Achsen bewegen läßt.
Kann ich zwischen 2 Workerthreads mit SetEvent/WFSO zu Synchrozwecken arbeiten?
-
Kann ich zwischen 2 Workerthreads mit SetEvent/WFSO zu Synchrozwecken arbeiten?
Mann, schrieb doch bitte SetEvent/WaitEvent. Ich musste wieder überlegen was wohl "WFSO" nun wieder bedeutet :p
Natürlich kannst Du mit SetEvent/WaitEvent synchronisieren. Du musst einfach in WaitEvent auch immer den Event "StopThread" einbeziehen damit Du nie einen kompletten Hänger bekommst.
Ich synchronisiere Threads immer so locker wie möglich... Ist wie bei einem Getriebe, ein bisschen Spiel muss sein damit es flutscht
Wenn Du Werte von einem Thread zum anderen übertragen willst, dann musst Du die Set/Get Funktionen mit einer CriticalSection schützen.
Mir hat das Buch "Win32 Multithreaded Programming" ISBN 1-56592-296-4 sehr geholfen.
-
weicher schrieb:
Wenn Du Werte von einem Thread zum anderen übertragen willst, dann musst Du die Set/Get Funktionen mit einer CriticalSection schützen.
Das ist mir bekannt, wird gemacht wenn nötig, paßt aber nicht zur Problemstellung hier.
Ich habe es jetzt so gelöst:
Jeder der beiden WTs erzeugt lokale CEvent Objekte. Diese bekommen jeweils im Konstruktor einen passenden Namen (3.Parameter lpszName) damit diese Threadübergreifend erkannt werden.
Gewartet wird mit WaitForSingleObject(Objektbezeichner, INFINITE)Sieht bis jetzt gut aus...
-
Also ich arbeite bei Multithreading eigentlich immer asynchron, d.h. jeder Thread hat eine Queue, die er regelmäßig abarbeitet. Auf die Art "flutscht" es eigentlich immer ganz gut.