Multithreading und GetMessage



  • AnfängerX schrieb:

    Gibt es noch weitere Vorteile der Windows API, außer Prioritäten?

    naja du kannst eben "alles" konfigurieren, das muss aber nicht unbedingt ein vorteil sein.

    Denn offensichtlich ist das ein unglaublich komplexes Thema, nur kann ich die Schwierigkeit noch nicht erkennen.

    die probleme fangen auch erst an, wenn mehrere threads auf eine variable zugreifen. wenn also 1500€ auf dem bankkonto liegen und thread1 900€ abheben will und thread2 1000€, dann zahlt die bank möglicherweise zuviel aus und das muss verhindert werden.



  • Hallo zusammen,

    vielen Dank für eure zahlreiche Hilfe und den neuen Link!

    Ich werde mich noch einmal in Ruhe mit dem Link beschäftigen. Aber wenn - jetzt nur beim drüber lesen - mutex oder CriticalSection nicht ordnungsgemäß funktionieren, dann verstehe ich die Komplexität meines Vorhabens... Allerdings stellt sich dann auch mein Programmierweltbild auf den Kopf. Denn wenn beispielsweise die Bibliothek <mutex> nicht funktioniert, funktionieren denn dann eigentlich alle anderen Bibliotheken richtig? Ich lese doch etwas falsch?! 😮
    Naja und in logischer Konsequenz kann ich dann natürlich auch nicht die einfache <thread> Bibliothek nutzen, sondern benötige die Windows API. Und ich darf mir etwas einfallen lassen, wie ich die Sychronisierung regle und welche Elemente überhaupt vor Mehrfach-Zugriff geschützt werden müssen. Vielleicht könntet ihr mir das noch mit einem kurzen "ja" bestätigen?

    Nochmal ganz lieben Dank! 👍 und ich habe mir da ja ein wunderschönes Projekt herausgesucht 😞


  • Mod

    AnfängerX schrieb:

    Aber wenn - jetzt nur beim drüber lesen - mutex oder CriticalSection nicht ordnungsgemäß funktionieren, dann verstehe ich die Komplexität meines Vorhabens... Allerdings stellt sich dann auch mein Programmierweltbild auf den Kopf. Denn wenn beispielsweise die Bibliothek <mutex> nicht funktioniert, funktionieren denn dann eigentlich alle anderen Bibliotheken richtig? Ich lese doch etwas falsch?! 😮

    Wer sagt, dass Mutex und CriticalSection NICHT gehen?
    Woraus schließt DU das?



  • Wohl aus Avoid CMutex, CEvent, CSemaphore and CCrticalSection, also die MFC-Implementierungen!!!

    Aber davon war ja in diesem Thema nie die Rede, denn die C++ Standard-Bibliotheken <thread> und <mutex> werden wohl korrekt umgesetzt worden sein.



  • von mutex und co rede ich gar nicht. du wirst schon merken, was ich meine, wenn da nachher fehler auftreten und du das ganze debuggen darfst.

    AnfängerX schrieb:

    und ich habe mir da ja ein wunderschönes Projekt herausgesucht 😞

    hast du ja auch. also mir macht sowas spaß!

    so kompliziert sind mutexes in der winapi aber auch nicht, du kannst sie also problemlos verwenden: https://msdn.microsoft.com/en-us/library/windows/desktop/ms686927(v=vs.85).aspx


  • Mod

    Th69 schrieb:

    Wohl aus Avoid CMutex, CEvent, CSemaphore and CCrticalSection, also die MFC-Implementierungen!!!

    Aber davon war ja in diesem Thema nie die Rede, denn die C++ Standard-Bibliotheken <thread> und <mutex> werden wohl korrekt umgesetzt worden sein.

    Ich gehe in vielen Dingen nicht mit Joseph konform. Wie auch hier...
    Joseph ist/war (ich weiß es nicht) sehr speziell. Ich glaube am liebsten würde er es lieben wenn alle noch Assembler programmieren... 😉



  • Martin Richter schrieb:

    Ich gehe in vielen Dingen nicht mit Joseph konform. Wie auch hier...
    Joseph ist/war (ich weiß es nicht) sehr speziell. Ich glaube am liebsten würde er es lieben wenn alle noch Assembler programmieren... 😉

    The Best Synchronization Is No Synchronization: Alternatives to semaphores, mutexes, and CRITICAL_SECTIONs

    http://www.flounder.com/no_synchronization.htm

    It is easier to reason about synchronization when you use protocols like Positive Handoff and Central Controller than if you try to reason about mutexes and semaphores. Because there is no explicit synchronization, there is no possibility of deadlock.

    Da ist schon was dran. Mit einem "Central Controller" bin ich immer sehr gut gefahren.



  • Th69 schrieb:

    Wohl aus Avoid CMutex, CEvent, CSemaphore and CCrticalSection, also die MFC-Implementierungen!!!

    In dem Artikel geht es hauptsächlich darum dass der Autor nicht verstanden hat wie man CSingleLock verwendet, daraus dann falsche Schlüsse zieht und behauptet dass CMutex und CCriticalSection "broken" wären. Das einzige was broken ist ist allerdings sein verständnis von CSingleLock .

    (OK, das ist nicht das einzige worum es in dem Artikel geht. Ein paar der anderen Punkte sind valide, aber für die meisten Anwendungen nicht von besonders grosser Bedeutung.)



  • Hallo zusammen,

    vielen Dank für eure zahlreichen Beiträge. 👍

    Bei mir ist es momentan leider etwas stressig, sodass ich nicht vor nächstem Wochenende dazu kommen werde, etwas zu programmieren. Mit euren zahlreichen Links sollte ich es aber schaffen, ich werde sowohl thread als auch die mutexes aus der Win API nehmen. Das sollte am Sinnvollsten sein.

    Wenn ihr also nicht noch weiter über den Autor des einen Links diskutieren wollt, könnt ihr das Thema schließen, ich steige bei der Diskussion leider aus.

    Ganz lieben Dank noch einmal!

    AnfängerX



  • Ich muss leider sagen, dass ich Mr. Newcomers Urteil weit mehr vertraue als hustbaers.



  • Es ist vollkommen egal wem du mehr vertraust. Das ist keine wischi-waschi Einschätzung wo es Meinungen geben kann. Das ist einfach so.
    CSingleLock ist wie std::unique_lock dafür gedacht dass man es auf den Stack legt. Lokale Variable innerhalb einer Funktion. Bzw. ganz explizit nicht dafür gedacht concurrent verwendet zu werden.

    Wer sich darüber aufregt dass es nicht thread-safe ist und/oder dass man damit nicht rekursiv locken kann, der hat das schlicht und ergreifend nicht verstanden.


  • Mod

    hustbaer schrieb:

    Th69 schrieb:

    Wohl aus Avoid CMutex, CEvent, CSemaphore and CCrticalSection, also die MFC-Implementierungen!!!

    In dem Artikel geht es hauptsächlich darum dass der Autor nicht verstanden hat wie man CSingleLock verwendet, daraus dann falsche Schlüsse zieht und behauptet dass CMutex und CCriticalSection "broken" wären. Das einzige was broken ist ist allerdings sein verständnis von CSingleLock .

    (OK, das ist nicht das einzige worum es in dem Artikel geht. Ein paar der anderen Punkte sind valide, aber für die meisten Anwendungen nicht von besonders grosser Bedeutung.)

    👍

    Genau... 🙂



  • EOP schrieb:

    Mit einem "Central Controller" bin ich immer sehr gut gefahren.

    ich habe mal etwas programmiert, bei dem sich die einzelnen threads bei einem "steuer-thread" in eine warteschleife eingetragen und dann aktiv mit sleep gewartet haben, bis sie an der reihe waren.

    ist das sowas? bing spuckt da irgendwie nur müll aus.



  • Bei mir ging es eigentlich nur um HTTP-threads.
    Die threads senden ihre Aufgabenanforderungen und Datenergebnisse per PostMessage an einen "Central Controller", der das verwaltet, Aufgaben zuteilt und neue Aufgabe versendet.
    Funktioniert auch mit 256 threads hervorragend und echt flott.



  • Hallo zusammen,

    lange ist es her, aber nachdem der Thread noch offen ist und ich am Verzweifeln, würde ich mich erneut sehr über eure Hilfe freuen.

    Grundsätzlich laufen die beiden Threads parallel ab und hypothetisch funktioniert es. In der Praxis jedoch sperrt Thread A, der die Auf- und Abbewegung des Balls steuert, ununterbrochene die Ressource bzw. das Fenster, sodass händische Eingaben nicht möglich sind, So ist es mir nicht möglich, das Programm zu schließen und ich sehe ununterbrochen das Windows-Ladesymbol.
    Implementiere ich in Thread A jedoch vor der Ressourcensperrung eine aufwändige Rechenaufgabe, kann ich das Programm wunderbar schließen oder andere händische Eingaben machen, nur hängt dann auch das Bild. 😞 😞

    #include <Windows.h>
    #include <tchar.h>
    #include <ctime>
    #include "Graphics.h"
    
    Graphics *bitte = NULL;
    CRITICAL_SECTION window;
    bool TAbbruch = false;
    
    LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMSG, WPARAM wParam, LPARAM lParam) {
    
    	switch (uMSG)
    	{
    	case WM_CLOSE:
    		if (MessageBox(hwnd, _T("Are you sure?"), _T("noPlan"), MB_OKCANCEL) == IDOK) {
    			DestroyWindow(hwnd);
    			PostQuitMessage(0);
    		}
    		return 0;
    	}
    
    	return DefWindowProc(hwnd, uMSG, wParam, lParam);
    }
    
    DWORD WINAPI ThreadProc() {
    
    	float y = 150;
    	float ySpeed = 0.0;
    
    	time_t previous = time(0);
    	time_t lag = 0.0;
    
    	while (!TAbbruch)
    	{
    		/*time_t current = time(0);
    		time_t elapsed = current - previous;
    		previous = current;
    		lag += elapsed;
    
    			while (lag >= 0.0000000000001) {
    			*/
    
    				ySpeed += 3.0;
    				y += ySpeed;
    
    				if (y > 600) {
    					y = 600;
    					ySpeed = -50;
    				}
    
    				EnterCriticalSection(&window);
    				bitte->cls(1.0, 1.0, 1.0, 1.0);
    				bitte->Ball(375.0f, y, 90);
    				LeaveCriticalSection(&window);
    
    				//lag -= 0.0000000000001;
    			//}
    
    	}
    
    	return 0;
    }
    
    int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pcmdline, int nCmdShow)
    {
    	WNDCLASSEX wndc;
    	ZeroMemory(&wndc, sizeof(WNDCLASSEX));
    	wndc.cbSize = sizeof(WNDCLASSEX);
    	wndc.style = CS_HREDRAW | CS_VREDRAW;
    	wndc.lpfnWndProc = WindowProc;
    	wndc.hInstance = hInstance;
    	wndc.hbrBackground = (HBRUSH) COLOR_WINDOW;
    	wndc.lpszClassName = _T("MainWindow");
    
    	RegisterClassEx(&wndc);
    
    	RECT rect = { 0, 0, 800, 600 };
    	AdjustWindowRectEx(&rect, WS_OVERLAPPEDWINDOW, false, WS_EX_OVERLAPPEDWINDOW);
    
    	HWND hwnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, wndc.lpszClassName, _T("DirectX"), WS_OVERLAPPEDWINDOW, 100, 100, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, hInstance, NULL);
    
    	if (!hwnd) {
    
    		DWORD err = GetLastError();
    		TCHAR output[100];
    		_stprintf_s(output, _T("%s") , err);
    
    		MessageBox(NULL, (LPCWSTR) output, NULL, MB_OK);
    
    		return -1;
    	}
    
    	bitte = new Graphics();
    	if (!bitte->Init(hwnd)) {
    		delete bitte;
    		return -1;
    	}
    
    	ShowWindow(hwnd, nCmdShow);
    
    	InitializeCriticalSection(&window);
    
    	HANDLE thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) ThreadProc, NULL, 0, NULL);
    
    	MSG msg = {};
    
    	while (GetMessage(&msg, NULL, 0, 0))
    	{
    
    		TranslateMessage(&msg);
    
    		EnterCriticalSection(&window);
    		DispatchMessage(&msg);
    		LeaveCriticalSection(&window);
    	}
    	TAbbruch = true;
    	Sleep(5000);
    
    	CloseHandle(thread);
    	DeleteCriticalSection(&window);
    	delete bitte;
    
    	return 0;
    }
    

    Ich bin um jeden Rat dankbar!



  • Ist doch klar: dein Thread ballert so schnell wie möglich durch die Schleife und hält dabei fast ununterbrochen die CriticalSection. Folglich bleibt fast keine Zeit mehr für die Nachrichtenschleife des Mainthreads; diese wird fast nur am Warten sein.

    PS: Du hast mindestens ein Data Race zwischen deinem Thread und dem Mainthread. Der Thread läuft auch noch, wenn das Fenster schon geschlossen wurde, folglich ist das HWND im Thread ungültig. TAbbruch muss außerdem atomic sein.


  • Mod

    Es gibt hier nur offene Threads. Also kannst Du auch einen neuen Anfangen!

    Also der Thread sollte nach Ausführung seines Zyklus seine time slice abgeben.

    Hier wäre Sleep(1) ein Kandidat. Gegen Sleep(0) spricht http://blogs.msdn.com/oldnewthing/archive/2005/10/04/476847.aspx aber würde auch gehen.

    @Biolunar: Eine Race Condition sehe ich nicht. Wo ist die? Beide wollen das gleiche. Und? Dafür gibt es die Critical Section!
    Oder verstehst Du was anderes under Race-Condition?
    https://de.wikipedia.org/wiki/Race_Condition

    Das Problem ist vermutlich einfach in der Priorisierung. Du möchtest das Inputs sofort behandelt werden. Also könntest Du die Thread Prio deines Input Threads erhöhen, und damit käme er öfters dran WENN eine Windows Nachricht ankommt.



  • Martin Richter schrieb:

    @Biolunar: Eine Race Condition sehe ich nicht. Wo ist die?

    if (!bitte->Init(hwnd)) { // Hier wird das HWND dem Graphics Objekt übergeben.
    
    // Im Thread:
    
    // Ich vermute mal, dass hier das HWND verwendet wird um das Fenster zu bemalen.
    EnterCriticalSection(&window);
    bitte->cls(1.0, 1.0, 1.0, 1.0);
    bitte->Ball(375.0f, y, 90);
    LeaveCriticalSection(&window);
    
    while (GetMessage(&msg, NULL, 0, 0)) 
    { 
        TranslateMessage(&msg); 
    
        EnterCriticalSection(&window); 
        DispatchMessage(&msg); 
        LeaveCriticalSection(&window); 
    } // Wenn das Programm aus diesem Block heraus geht, ist das HWND ungültig, weil das Fenster zerstört wurde.
    
    // Hier kann der Thread noch auf das ungültige HWND zugreifen und tut es vermutlich auch, da die
    // CriticalSection im Hauptthread verlassen wurde.
    


  • das mit dem ungültigen hwnd stimmt, dachte aber eigentlich die sleep-Funktion würde das lösen... atomic sagt mir nichts, ist das das: https://msdn.microsoft.com/en-us/library/windows/desktop/ff476334(v=vs.85).aspx
    oder hättest du ein Beispiel?

    time slice sagt mir leider auch nichts und das mit der Priorität probiere ich gleich. und klar, ballert mein thread durch die Schleife in die CriticalSection, aber wenn er das nicht tut, hängt das Bild und das will ich ja auch nicht ... 😞

    ganz lieben Dank, freue mich über weitere Hilfe



  • LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMSG, WPARAM wParam, LPARAM lParam) {
    
    	switch (uMSG)
    	{
    	case WM_CLOSE:
    		if (MessageBox(hwnd, _T("Are you sure?"), _T("noPlan"), MB_OKCANCEL) == IDOK) {
    			TAbbruch = true;
    			Sleep(5000);
    			DestroyWindow(hwnd);
    			PostQuitMessage(0);
    		}
    		return 0;
    	}
    
    	return DefWindowProc(hwnd, uMSG, wParam, lParam);
    }
    [code="cli"]
    

    das ist vermutlich besser für den hwnd


Anmelden zum Antworten