WinAPI und Multithreading Synkronisationsproblem



  • Hallo ich habe unter Linux die PThreads verwendet und benutze da hauptsächlich mutex und conditions...

    jetzt will ich das unter Windows programmieren...

    In der API hab ich CriticalSections gefunden... die ich anstelle von mutex(linux) verwende...
    Was aber verwende ich anstelle von conditions? Auch in der API finde ich CONDITION_VARIABLE.. leider wird diese nicht in winXP zur Verfügung gestellt...

    ...also habe ich versucht mit Events rumzuspielen.

    Was muss ich dabei beachten? Denn ich denke, dass es prinzipiell schon funktioniert.. allerdings wenn sich ein Thread beenden, bekomme ich eine Fehlermeldung, dass mein Programm beendet werden musste... Problembericht senden!? DIALOG... leider liefert der mir keine genaue Aussage über den Fehler...

    ...also ich weiss nicht genau, was schief geht! 👎

    // Am Start
    HANDLE cond = CreateEvent( NULL, FALSE, FALSE, NULL );
    
    // Zwischen drin
    // Thread 1
    WaitForSingleObject( cond, INFINITY );
    
    // Thread 2
    SetEvent( cond );
    
    // Am Ende
    CloseHandle( cond );
    
    DWORD WINAPI Thread::static_runner( LPVOID data )
    {
        // Hier rufe ich Thread 1 und 2 auf...
    
        // Wenn jetzt einer von beiden diese stelle hier erreicht
        // Schmiert mir das Programm ab... wenn ich versuche
        Sleep( 2000 );
        // oder
        ExitThread( 0 );
        // aufzurufen... Ausgabe wie
        std::cout << "Huhu" << std::endl;
        // funktionieren aber noch
        return 0;
    }
    


  • Hab hier jetzt eine Loesung zusammengeschusster: 👍

    #include <iostream>
    #include <stdlib.h>
    #include <windows.h>
    
    using namespace std;
    
    class Runnable
    {
    	public:
    		virtual void run() = 0;
    };
    
    class Thread
    {
    	private:
    		HANDLE th;
    		DWORD mtid;
    		Runnable* mr;
    	public:
    		Thread( Runnable& r ){
    			th = 0;
    			mr = &r;
    		}
    
    		~Thread(){
    			if( th != 0 ){
    				CloseHandle( th );
    			}
    		}
    
    		static DWORD WINAPI static_caller( LPVOID data ){
    			Runnable* r = (Runnable*)data;
    			r->run();
    			cout << " *** THREAD BEENDET ***" << endl;
    			ExitThread( 0 );
    			return 0;
    		}
    
    		void start(){
    			th = CreateThread( 0, 0,
    				static_caller,
    				(LPVOID)mr,
    				0,
    				&mtid );
    		}
    };
    
    class Semaphor
    {
    	private:
    		int mittel;
    		CRITICAL_SECTION cs;
    		HANDLE condition;
    
    		void lock(){
    			EnterCriticalSection( &cs );
    			cout << " > lock" << endl;
    		}
    		void unlock(){
    			cout << " < unlock" << endl;
    			LeaveCriticalSection( &cs );
    		}
    	public:
    		Semaphor( int m ){
    			mittel = m;
    			InitializeCriticalSection( &cs );
    			condition = CreateEvent( NULL, FALSE, FALSE, NULL );
    		}
    
    		~Semaphor(){
    			CloseHandle( condition );
    			DeleteCriticalSection( &cs );
    		}
    
    		void erwerben(){
    			lock();
    			while( mittel <= 0 ){
    				unlock();
    				WaitForSingleObject( condition, INFINITE );
    				lock();
    			}
    			mittel--;
    			unlock();
    		}
    
    		void zurueckgeben(){
    			lock();
    			mittel++;
    			unlock();
    			SetEvent( condition );
    		}
    };
    
    class Programm : public Runnable
    {
    	private:
    		static Semaphor* sem;
    		int mZeit;
    		int mId;
    	public:
    		Programm( int zeit, int id ){
    			mZeit = zeit;
    			mId = id;
    		}
    
    		virtual ~Programm(){
    		}
    
    		void run(){
    			Sleep( mZeit );
    			cout << "Ich bin Thread: " << mId << endl;
    
    			if( mId == 1 ){
    				cout << "Thread: " << mId << " gebe Sem zurueck" << endl;
    				sem->zurueckgeben();
    			}else{
    				cout << "Thread: " << mId << " erwerbe Sem" << endl;
    				sem->erwerben();
    				cout << "Thread: " << mId << " gebe Sem zurueck" << endl;
    				sem->zurueckgeben();
    			}
    
    			cout << "Thread: " << mId << " verabschiedet sich" << endl;
    		}
    };
    
    Semaphor* Programm::sem = new Semaphor( 0 );
    
    int main( int argc, char** argv )
    {
    	Programm p1( 3200, 1 );
    	Programm p2( 1700, 2 );
    	Programm p3( 1500, 3 );
    
    	Thread t1( p1 );
    	Thread t2( p2 );
    	Thread t3( p3 );
    
    	t1.start();
    	t2.start();
    	t3.start();
    
    	while( true ){
    		cout << "Schlafe..." << endl;
    		Sleep( 20000 );
    	}
    }
    


  • Semaphoren musst du nicht nachbauen, die gibts schon fertig.
    (Auch Mutexe, obwohl da, wenn nicht prozessübergreifend benutzt, eher CriticalSections anzuwenden sind, weil sie performanter sind).

    http://msdn.microsoft.com/en-us/library/ms686360(VS.85).aspx
    Simon

    Edit: Ausserdem ist es ratsam RAII für die "Lock" Geschichten zu verwenden.



  • boost::thread bzw boost::mutex sind zwei heiße Tipps.



  • Also bis jetzt läuft die Lösung ganz gut.. und ich bin an keine extra Bibliothek gebunden 😉

    😃 am liebsten wären mir ja systemcalls 😋

    also falls wer ein gutes tut hat 🕶



  • Sorry, daß ich mir nicht die Muße genommen habe, Deinen Code zu lesen.

    Dafür hab ich Deinen Wunsch erhört:

    matti83 schrieb:

    😃 am liebsten wären mir ja systemcalls 😋

    also falls wer ein gutes tut hat 🕶

    Bitteschön, hier:
    http://www.jliforum.de/board/viewtopic.php?p=63665
    http://www.codeworx.org/cpp_tuts_1_5.php
    Multithreading for Rookies: http://msdn.microsoft.com/en-us/library/ms810438.aspx

    HTH,
    Martin



  • Also bis jetzt läuft die Lösung ganz gut.. und ich bin an keine extra Bibliothek gebunden

    Wenn es dich nicht stört dass du ne Race-Condition drinnen hast...



  • eine race condition?

    weitere Erläuterung bitte.. und warum ist das schlecht?

    @Mmacher - danke für die links...


Anmelden zum Antworten