Kann man einem Thread eine CPU zuordnen??? Bsp. Primberechnung



  • Dieser Thread wurde von Moderator/in Phoemuex aus dem Forum C++ in das Forum WinAPI verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • Im Buch "Windowsprogrammierung" von Charles Petzold gibt es ein Kapitel 20 "Multitasking und Multithreading", dort gibt es einen Unterpunkt "Seiteneffekte":

    ...
    Es sieht so aus, als müsse der gleichzeitige Zugriff zweier Threads auf dasselbe Fenster durch einen kritischen Abschnitt verhindert werden. Experimente, die ich in diese Richtung angestellt habe, zeigen aber, dass Windows bei grafischen Zeichenfunktionen selbst für die Serialisierung sorgt: Zu jedem Zeitpunkt kann immer nur ein Thread in ein Fenster zeichnen. Ein Zweiter Thread, der da gleichzeitig versucht, bleibt so lange blockiert, bis der erste Thread seine Operationen abgeschlossen hat.

    Diese Aussage scheint zu erklären, warum die CPU Auslastung auf etwa die Hälfte beschränkt bleibt. Während der erste Thread zeichnet, wartet der zweite Thread und der entsprechende CPU Kern hat währenddessen nichts zu tun - die Auslastung sinkt.
    Ich habe das Programm bei mir zum Laufen gebracht, um zu sehen, wie es funktioniert. Hier mein Makefile:

    all:
    	mingw32-gcc main.c -o main.exe -mwindows
    

    Ich beobachte im Prinzip dasselbe Verhalten wie rom4o. Wenn ich beide Threads aktiviere, sinkt bei meinem Centrino Duo 1.8 GHz die CPU Auslastung auf etwa 30 Prozent. Wahrscheinlich habe ich langsameren Rechner/Grafikkarte und die beiden Threads müssen entsprechend länger warten...



  • Hallo Leute, erstmal Danke für die vielen Antworten,
    na ist ja auch ein aktuelles Thema.

    @unskilled
    Also der folgende Befehl

    Rectangle (hdc1 ,rand()%200 ,rand()%200 ,rand()%200, rand()%200);
    

    funktioniert wunderbar in der Version 6 von MS Visual C++,
    mit der arbeite ich nämlich. Ich weiss, die ist sehr alt schon 10Jahre
    aber ich fahre bis jetzt noch ganz gut damit, will mir aber ein
    aktuelles Visual Studio zulegen.

    Der Befehl funktioniert so
    Rectangle (hdc1 ,rect.left ,rect.top ,rect.right, rect.bottom);
    hdcl ist in meinem Fall das Zielobjekt, in das gezeichnet werden soll
    und die einzelnen Einträge werden mit zufälligen Zahlen zwischen 1-200 belegt.
    Dabei kann es auch sein, dass einige Rechtecke nicht gezeichnet werden, wenn
    left>right oder top>bottom ist, aber bei der Zahl an Rechtecken die gezeichnet werden ist das nicht wichtig.

    @hustbaer
    Hallo, ja ich weiss, dass ich nix synchronisiert habe, konnte das ja bis dato auch nicht. Aber ich befasse mich ja fortwährend mit dem Thema.
    Und zu den Primzahlen später.

    @Phoemux, danke sehr fürs verschieben des Threads.... 🙂

    @abc.w
    Sehr schön, dass es bei dir läuft und du es probiert hast.
    Damit wäre ja dann meine Frage geklärt.

    Schade...aber ich arbeite nun an
    meiner ursprünglichen Idee, das Programm zur Primzahlenberechnung.
    Die Singlecore Variante habe ich fertig und läuft mit halber CPU-Auslastung wie gewohnt.

    In der Dualcore-Variante möchte ich das Problem 3teilen,
    3 Threads, die ersten beiden prüfen wie schon gesagt die jeweils
    übernächste ungerade Zahl und bei "true" sollen die Ergebnisse in eine Queue.
    Aus dieser soll dann der dritte Thread lesen und die Ergebnisse zeichnen.

    Bis jetzt weiss ich noch nicht wie ich die Threads synchronisieren soll.
    Ich möchte das wie in folgendem Beispiel haben:
    ...
    35
    37prim angenommen Thread1 rechnet noch
    39 und Thread2 ist fertig aber soll auf Thread1 warten bis der mit 41 beginnt
    Nun, fangen beide Threads mit jeweils 41 und 43 an
    41prim angenommen Thread1 braucht länger dann soll
    43prim Thread2 sein Ergebnis erst in die Queue schreiben wenn 41 drin steht
    sonst ist die Reihenfolge falsch
    45
    47prim
    49
    ...

    Ich weiss, dass ich so nicht die 100%Auslastung erzielen werde aber auf jeden Fall mehr als 50%.
    Die Frage ist, wie ich den Einen auf den anderen Thread warten lasse und umgekehrt?
    Ich dachte mir vielleicht mit SetEvent() und einer "Wait Function" oder ähnlich.
    Vielleicht hat ja einer von euch Ahnung davon?

    Vielen Dank,

    bb rom4o ...



  • rom4o schrieb:

    Bis jetzt weiss ich noch nicht wie ich die Threads synchronisieren soll.
    Ich möchte das wie in folgendem Beispiel haben:
    ...
    35
    37prim angenommen Thread1 rechnet noch
    39 und Thread2 ist fertig aber soll auf Thread1 warten bis der mit 41 beginnt
    Nun, fangen beide Threads mit jeweils 41 und 43 an
    41prim angenommen Thread1 braucht länger dann soll
    43prim Thread2 sein Ergebnis erst in die Queue schreiben wenn 41 drin steht
    sonst ist die Reihenfolge falsch
    45
    47prim
    49
    ...

    mach doch einen problemerzeuger und einen lösungsempfänger. der erzeuger gibt die probleme der reihe nach raus. der empfämger nimmt sie auch ungeordnet an, aber sortiert sie vorm anzeigen, also der hält falsch eingereite lösungen einfach kurz zurück.

    rom4o schrieb:

    Ich weiss, dass ich so nicht die 100%Auslastung erzielen werde aber auf jeden Fall mehr als 50%.

    sag das nicht. nehmen wir an, du checkst primzahlen im bereich um eine milliarde per triel division. da sind die primzahlen schon selten. ca jede zwanzigste ist prim. und bei primzahlen machste 15000 divisionen. viell viele zahlen haben aber kleine teiler. und die sind praktisch sofort fertig. von deinen 20 prozessoren würden die meiste zeit 19 leer warten auf den einen glücklichen, der ne primzahl getroffen hat.
    deswegen sollen sich die anderen rugig beim problemversorger bedienen dürfen und schonmal vorauslaufen.



  • Hallo volkard,
    Danke sehr für die rasche Antwort.
    Stimmt das leuchtet ziehmlich ein. Was du da vorschlägst fordert natürlich
    eine ganz neue Struktur meines Programms.
    Abgesehen davon habe ich noch keine Ahnung, wie ich die Geschichte mit den Threads händeln werde.
    Jedoch scheint mir dein Vorschlag sehr viel effektiver zu sein, als mein Ansatz. 🙂
    Also werde ich, dem jeweils wartenden CPU-Kern die nächste Zahl zum berechnen geben? So habe ich dies verstanden. Dafür muss man ja ermitteln welcher Kern gerade frei ist, hmmhmmmmm "nächste Frage"?

    Für die, die es interessiert. Hier ist mein SingleCoreCode....nicht anspruchsvoll
    aber leicht erweiterbar.

    // PrimSingleCore.cpp : Definiert den Einsprungpunkt für die Anwendung.
    //
    
    #include "stdafx.h"
    #include <windows.h>
    #include <stdlib.h>
    #include <math.h>
    
    LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
    
    HINSTANCE hInstGlobal;
    HWND hWindow, hButtonStart, hButtonStop, hButtonExit;
    HDC hdc;
    static RECT rect, rect1;
    SYSTEMTIME systime,systimeold;			//time-variable
    int hDiff = 0;
    int mDiff = 0;
    int sDiff = 0;
    int msDiff = 0;
    CONST aim = 500000;						//Zielzahl
    int count;								//Anzahl
    char *Gstring;							//globaler String
    bool th1runs;
    bool flag1;
    const UINT TimerSec = 1;				//TIMER
    
    int APIENTRY WinMain(HINSTANCE hInstance,
    					 HINSTANCE hPrevInstance,
    					 LPSTR lpCmdLine,
    					 int nCmdShow )
    {
    	hInstGlobal = hInstance;
    	WNDCLASS WndClass;
    	WndClass.style = 0;
    	WndClass.cbClsExtra = 0;
    	WndClass.cbWndExtra = 0;
    	WndClass.lpfnWndProc = WndProc;
    	WndClass.hInstance = hInstance;
    	WndClass.hbrBackground = (HBRUSH) (COLOR_WINDOW+11);
    	WndClass.hCursor = LoadCursor (NULL, IDC_ARROW);
    	WndClass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    	WndClass.lpszMenuName = 0;
    	WndClass.lpszClassName = "WinProg";
    
    	RegisterClass(&WndClass);
    
    		Gstring = new char[20];
    		SetTimer(hWindow, TimerSec, 14, NULL);				//TIMER
    
    	hWindow = CreateWindow("WinProg","PrimDualCore",
    							WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX,
    							0,0,800,600,NULL,NULL,
    							hInstance, NULL);
    
    	ShowWindow (hWindow, nCmdShow);
    	UpdateWindow (hWindow);
    	MSG Message;
    	while (GetMessage(&Message, NULL, 0, 0))
    	{
    		DispatchMessage(&Message);
    	}
    	return (Message.wParam);
    }
    
    void calcDiff()		//Zeitschieber-Methode
    	{
    		hDiff = systime.wHour-systimeold.wHour;
    		mDiff = systime.wMinute-systimeold.wMinute;
    		sDiff = systime.wSecond-systimeold.wSecond;
    		msDiff= systime.wMilliseconds-systimeold.wMilliseconds;
    
    		if(msDiff<0){sDiff--; msDiff=msDiff+1000;}
    		if(sDiff<0){mDiff--; sDiff=sDiff+60;}
    		if(mDiff<0){hDiff--; mDiff=mDiff+60;}
    		if(hDiff<0){hDiff=hDiff+24;}
    	}
    
    bool Prim(int zahl)
    {
    	bool devided = false;
    //	erg = sqrt(aim);
    
    	for(int k=3;k<(sqrt(zahl)+1);k=k+2)
    	{
    		if((zahl%k) == 0){ devided=true; k=zahl;}
    	}
    
    	return !devided;
    }
    
    DWORD WINAPI ThreadProc1( LPVOID pvoid )
    {
    	flag1 = false;
    	InvalidateRect(hWindow, &rect1, TRUE);
    	TEXTMETRIC tm;
    	GetTextMetrics (hdc, &tm);
    	int i;		//Laufvariable
    	int ix,iy;
    	count=1;	//wegen der 2
    	ix = 0;
    	iy = 0;
    	char *string;
    	string = new char[20];
    
    	{							// einmalige Ausgabe der 2 da diese nicht im DB von Prim(2) ist
    		hdc = GetDC (hWindow);
    		SetBkColor (hdc, RGB(236,233,216));
    		wsprintf(string,"%01d",2);
    		TextOut (hdc, ix, iy, string, lstrlen(string));
    		iy = iy + tm.tmHeight;
    		ReleaseDC (hWindow, hdc);
    	}
    
    		for (i=3;i<=aim;i=i+2)
    		{
    			if(Prim(i))
    			{
    				count++;
    				hdc = GetDC (hWindow);
    				wsprintf(string,"%01d",i);
    				SetBkColor (hdc, RGB(236,233,216));
    				TextOut (hdc, ix, iy, string, lstrlen(string));
    				iy = iy + tm.tmHeight;
    
    				if ((iy/tm.tmHeight) == 33)
    				{
    					iy = 0;
    					ix = ix + 90;
    				}
    				if(ix>770) { ix=0; iy=0;}
    				ReleaseDC (hWindow, hdc);
    			}
    		}
    
    	flag1 = true;
    	GetSystemTime(&systime);		//take time END
    	calcDiff();
    	InvalidateRect(hWindow, &rect1, TRUE);
    
    	delete [] string;
    	th1runs = false;
    	return NULL;
    }
    
    LRESULT CALLBACK WndProc (HWND hWnd, UINT uiMessage,
    						  WPARAM wParam,LPARAM lParam)
    {
    	static HANDLE hThread1;
    	switch(uiMessage)
    	{
    		case WM_SIZE:
    		{
    			rect.left = 0;			//x-links	TEST
    			rect.top = 0;			//y-oben	TEST
    			rect.right = 800;		//x-rechts	TEST
    			rect.bottom = 600;		//y-unten	TEST
    
    			rect1.left = 360;		//x-links	TEST
    			rect1.top = 530;		//y-oben	TEST
    			rect1.right = 800;		//x-rechts	TEST
    			rect1.bottom = 600;		//y-unten	TEST
    			return 0;
    		}
    
    		case WM_CREATE:
    			hButtonStart = CreateWindow	("BUTTON","START",
    										 WS_CHILD | WS_VISIBLE |
    										 BS_PUSHBUTTON,
    										 10,540,100,20,
    										 hWnd,(HMENU) 1,
    										 hInstGlobal, NULL);
    
    			hButtonStop = CreateWindow ("BUTTON","STOP",
    										 WS_CHILD | WS_VISIBLE |
    										 BS_PUSHBUTTON,
    										 120,540,100,20,
    										 hWnd,(HMENU) 2,
    										 hInstGlobal, NULL);
    
    			hButtonExit = CreateWindow("BUTTON","Exit",
    										WS_CHILD | WS_VISIBLE |
    										BS_PUSHBUTTON,
    										250,540,80,20,
    										hWnd,(HMENU) 3,
    										hInstGlobal, NULL);
    			return 0;
    
    		case WM_TIMER:
    		{
    			//InvalidateRect(hWnd, &rect1, TRUE);	// bewirkt die Aktuallisierung im Bereich von rect1				//TIMER
    			return 0;
    		}
    
    		case WM_PAINT:
    		{
    			HDC hdc;
     			PAINTSTRUCT ps;
    			char *WMstring;
    			WMstring = new char[1];
    			WMstring[0] = 169;			// das (C)reated	
    
    			hdc = BeginPaint (hWnd, &ps);							//BEGIN PAINT
    				SetBkColor (hdc, RGB(236,233,216));
    				SetTextColor (hdc, RGB(180,0,0));
    				TextOut (hdc, 360, 540, "time: ", lstrlen("time: "));
    				if(flag1)
    				{
    					wsprintf( Gstring , "%02d:%02d:%02d:%03d",hDiff,mDiff,sDiff,msDiff);
    					TextOut (hdc, 400, 540, Gstring, lstrlen(Gstring));
    				}
    				SetTextColor (hdc, RGB(0,180,0));
    				TextOut (hdc, 540, 540, "count: ", lstrlen("count: "));
    				if(flag1)
    				{
    					wsprintf( Gstring , "%01d",count);
    					TextOut (hdc, 590, 540, Gstring, lstrlen(Gstring));
    				}
    
    			SetTextColor (hdc, RGB(187,187,187));
    			SetBkColor (hdc, RGB(236,233,216));			//Rot=236 Grün=233 Blau=216 (standart Hellgrau)
    			TextOut (hdc, 520+184,540, WMstring, 1);
    			TextOut (hdc, 520+200,540, "by rom4o", 8);
    			EndPaint (hWnd, &ps);									//END PAINT
    			delete WMstring;
    			return 0;
    		}
    
    		case WM_COMMAND:
    			if (HIWORD(wParam) == BN_CLICKED)
    			{
    				if ( (LOWORD(wParam) == 1) && (th1runs == false) )
    				{
    					hdc = GetDC (GetParent((HWND) lParam));
    					InvalidateRect(hWnd, &rect, TRUE);
    					DWORD dwThreadParam1 = 1;
    					DWORD dwThreadID1;
    
    					th1runs = true;
    					GetSystemTime(&systimeold);		//take time BEGIN
    					hThread1 = CreateThread (NULL, 0, ThreadProc1,
    											&dwThreadParam1, 0, &dwThreadID1);
    
    				}
    
    				if (LOWORD(wParam) == 2)
    				{
    					TerminateThread (hThread1, 0);
    					th1runs = false;
    				}
    
    				if (LOWORD(wParam) == 3)
    				{
    					SendMessage (GetParent((HWND)lParam), WM_DESTROY ,0 ,0);
    				}
    			}
    			return 0;
    
    		case WM_DESTROY:
    			PostQuitMessage(0);
    			return 0;
    
    		default:
    			return DefWindowProc (hWnd, uiMessage, wParam, lParam);
    	}
    

    Nun denn vielen Dank für den Tip, ich grüble weiter und gehen nun erstmal zu Bett.

    grüße rom40



  • rom4o schrieb:

    Also werde ich dem jeweils wartendem CPU-Kern die nächste Zahl zum berechnen geben? So habe ich dies verstanden. Dafür muss man ja ermitteln welcher Kern gerade frei ist,....haha nächste Frage.

    ich denke etwa an sowas:
    alle threads legen bei programmstart los.
    jeder thread macht nur for(;;) { holeAufgabe(); rechne(); gibErgebnis(); }
    holeAufgabe und gibErgebnis schützen sich einfach durch CreateMutex und ihre freunde.
    das heißt, daß das erzeugen einer aufgabe nicht von einem bestimmten thread zu geschehen hat, sondern da arbeitet immer der, der gerade was braucht.

    evtl hängt zusätzlich ein anzeigethread rum, der alle userinteraktion aus einer hand zu machen hat. der kann natürlich auf die datenstrukturen von holeAufgabe und gibErgebnis auch zugreiifen. aber immer schön mit mutexen geschützt.



  • rom4o, hast du denn noch eine konkrete Frage?



  • @volkard

    jeder thread macht nur for(;;) { holeAufgabe(); rechne(); gibErgebnis(); }

    Das ist eine sehr gute Idee und ich werde versuchen das so zu implementieren.
    Jedoch habe ich erstmal ein grundlegendes Problem zu lösen.

    Hallo Leute ich habe nun mal in einem Programm versucht,
    die Berechnung von Primzahlen auf zwei Threads aufzuteilen. So kann man dann die Threads
    einzelnen CPU-Kernen zuordnen.
    Mein Ziel ist ja immernoch den Prozessor komplett auszulasten.

    Hier der Code:

    // prim_mutex_dualcore.cpp : Definiert den Einsprungpunkt für die Konsolenanwendung.
    //
    
    #include "stdafx.h" 
    #include <iostream>
    #include <windows.h>
    #include <math.h>
    using namespace std;
    
    SYSTEMTIME systime,systimeold;			//time-variable
    int hDiff = 0;
    int mDiff = 0;
    int sDiff = 0;
    int msDiff = 0;
    
    int count = 1;			// 1 weil die 2 nicht berechnet wird
    int c=3;
    int aim = 1000;
    //int aim = 2000000;
    
    HANDLE mutex = CreateMutex( NULL, FALSE, NULL );
    
    void calcDiff()		//Zeitschieber-Methode
    	{
    		hDiff = systime.wHour-systimeold.wHour;
    		mDiff = systime.wMinute-systimeold.wMinute;
    		sDiff = systime.wSecond-systimeold.wSecond;
    		msDiff= systime.wMilliseconds-systimeold.wMilliseconds;
    
    		if(msDiff<0){sDiff--; msDiff=msDiff+1000;}
    		if(sDiff<0){mDiff--; sDiff=sDiff+60;}
    		if(mDiff<0){hDiff--; mDiff=mDiff+60;}
    		if(hDiff<0){hDiff=hDiff+24;}
    	}
    
    bool Prim(int zahl)
    {
    	bool devided = false;
    
    	for(int k=3;k<(sqrt(zahl)+1);k=k+2)
    	{
    		if((zahl%k) == 0){ devided=true; k=zahl;}
    	}
    
    	return !devided;
    }
    
    DWORD WINAPI ThreadProc1( LPVOID pvoid )
    {
        while(c<=aim)
        {
    		if ( WaitForSingleObject( mutex, INFINITE ) == WAIT_OBJECT_0 )	// Mutex-Zugriff holen
            {
                if(Prim(c))
    			{
    				cout << "T1" << " : " << c <<endl;				// Ausgabe der Primzahl
    				count++;
    			}
                c=c+2;
                ReleaseMutex( mutex );		// Mutex wieder freigeben
            }
    //        Sleep(10);
        }
        return 0;
    }
    
    DWORD WINAPI ThreadProc2( LPVOID pvoid )
    {
        while(c<=aim)
        {
            if ( WaitForSingleObject( mutex, INFINITE ) == WAIT_OBJECT_0 )	// Mutex-Zugriff holen
            {
                if(Prim(c))
    			{
    				cout << "T2" << " : " << c <<endl;				// Ausgabe der Primzahl
    				count++;
    			}
                c=c+2;
                ReleaseMutex( mutex );		// Mutex wieder freigeben
            }
    //        Sleep(3000);
        }
        return 0;
    }
    
    void main()
    {
        // Threads erzeugen
    	GetSystemTime(&systimeold);		//take time BEGIN
        cout << "Thread1 startet..."<<endl;
        DWORD dwThreadParam1 = 1;
        HANDLE hThread1 = CreateThread (NULL,0,ThreadProc1,&dwThreadParam1,0,NULL);
    	SetThreadAffinityMask(hThread1, 1);
    
        cout << "Thread2 startet..."<<endl;
        DWORD dwThreadParam2 = 2;
        HANDLE hThread2 = CreateThread (NULL,0,ThreadProc2,&dwThreadParam2,0,NULL);
    	SetThreadAffinityMask(hThread2, 2);
    
        // Auf Threads warten
        WaitForSingleObject( hThread1, INFINITE );
        WaitForSingleObject( hThread2, INFINITE );
    
    	GetSystemTime(&systime);		//take time END
    	calcDiff();
    	cout << "Time: " << hDiff << ":" << mDiff << ":" << sDiff << ":" << msDiff << endl;
    	cout << "Anzahl: " << count <<endl;
    
        // Thread-Handles schließen
        CloseHandle( hThread1 );
        CloseHandle( hThread2 );
    
        // Mutex zerstören
        CloseHandle( mutex );
    
    	TerminateThread (hThread1, 0);
    	TerminateThread (hThread2, 0);
    }
    

    Nun habe ich als globale Variable "c" genommen, welches von jedem Thread um 2 inkrementiert wird.
    Diese Inkrementierung ist durch ein Mutex abgesichert.
    Mein Problem ist nun, dass immer nur ein Thread rechnet weil er auf den anderen wartet.

    Wie kann ich dieses Problem lösen?
    Mir fällt gerade überhaupt nichts ein.
    Wenn man die Textausgabe weglässt, ist das Programm schon sehr schnell.

    Ich habe eine Timetake-Funktion eingebaut, die die Rechenzeit anzeigt.
    Da wäre auch noch die Frage wie man in der Konsole die Integerwerte konvertiert ausgibt?
    Jetzt ist die Ausgabe so: "Time: 0:0:12:287", ich will die aber so haben "Time: 00:00:12:287".

    Vielen Dank für Ratschläge.

    grüße rom4o



  • rom4o schrieb:

    Mein Problem ist nun, dass immer nur ein Thread rechnet weil er auf den anderen wartet.

    Du brauchst den Funktionsaufruf von "Prim(c)" ja nicht mit dem Mutex zu schützen. Du könntest also den Mutex holen, den Wert von "c" in einer neuen temporären Variable speichern, "c" erhöhen und den Mutex zurückgeben. Dann führst du "if (Prim(old_c))" aus, währenddessen kann sich der andere Thread schon den Mutex holen.
    Das Problem dabei wäre nur, dass die Konsolen-Ausgabe durcheinander-geraten kann. Eine Lösung dafür wäre, erst alle Primzahlen in einem Container (entweder auch durch einen Mutex abgesichert oder jeder Thread hat seinen eigenen Container, die am Schluss zusammengefügt werden) zu speichern und erst nach den ganzen Berechnungen auszugeben.



  • int getNextCandidate()
    {
      WaitForSingleObject( mutex, INFINITE );
      c=c+2;
      int r=c;
      ReleaseMutex( mutex );
      return c;
    }
    void printPrime( int prime )
    {
      WaitForSingleObject( mutex, INFINITE );
      cout<<prime<<' ';
      ReleaseMutex( mutex );
    }
    
    bool Prim(int zahl)
    {
    	bool devided = false;
    
    	for(int k=3;k<(sqrt(zahl)+1);k=k+2)
    	{
    		if((zahl%k) == 0){ devided=true; k=zahl;}
    	}
    
    	return !devided;
    }
    
    DWORD WINAPI ThreadProc( LPVOID pvoid )
    {
        int cc=getNextCandidate();
        while(cc<=aim)
        {
                if(Prim(cc))
                   printPrime(cc);
            cc=getNextCandidate();
        }
        return 0;
    }
    


  • Nimm OpenMP, das macht das Leben viel einfacher... keine Gedanken mehr über Mutexe verlieren...
    Ab VS2010 siehe auch PPL...



  • Wo steht geschrieben, dass die GDI multiCPU-Fähig geschweige den Threadsafe ist?

    Den Satz vermisse ich seit über 20 Jahren.



  • @Badestrand: hab mich nach deinem Tip schnell rangemacht das umzusetzen und
    dann kam auch schon die Lösung von volkmar

    @Jochen Kalmbach
    Ja werde mich auch bald damit beschäftigen, aber ich will erstmal versuchen alles was möglich ist aus der WinApi herauszuholen.

    @CStern
    Ähm, habe ich das behauptet?
    Aber die Zuordnung der einzelnen Threads zu spezifischen Kernen, müsste doch
    theoretisch den Prozessor voll auslasten?
    Ich habe auch in meinen Tests die cout-Ausgabe herausgenommen.

    Hallo volkmar,
    danke für diese elegante Lösung.
    Es funktioniert. Aber es ist nichts schneller als vorher.
    Wenn ich die Ausgabe rausnehme ist zwar alles viel schneller aber nur halbe Prozessorauslastung.
    Ich kann mir das jetzt nicht erklären? Irgendwas muss schief laufen.

    Dazu habe ich noch count++; in deine print-Methode eingebaut
    Code:

    void printPrime( int prime )
    {
    	WaitForSingleObject( mutex, INFINITE );
    	cout<<prime<<"  ";
    	count++;
    	ReleaseMutex( mutex );
    }
    

    Das Problem ist, dass manchmal einige Werte doppelt berechnet werden.
    Ich habe mal mehrmals bis 2000000 berechnen lassen.
    count kommt auf folgende Werte: 149123,149058,149081,149066...usw.
    In einem Puffer könnte man natürlich die doppelten Ergebnisse aussortieren,
    aber wie kann es zu dieser Doppelberechnung bei deiner Verteilung kommen?

    Vielen Dank wieder für Ideen.

    Grüße rom4o



  • int getNextCandidate()
    {
      WaitForSingleObject( mutex, INFINITE );
      int r=c;
      c=c+2;
      ReleaseMutex( mutex );
      return r;
    }
    

    Ich denke, so war's gemeint.

    Und ich würde unterschiedliche Mutexe für c-Beschützung und Ausgabe nehmen.



  • evtl ist noch

    volatile int c=3;
    

    nötig.



  • Hallo, ja Badestrand das war das Problem.
    Hätte selber drauf kommen müssen 🙄
    Danke euch beiden für die Tips.
    Das Problem mit der halben Prozessorauslastung ist mir allerdings immernoch
    ein Rätsel.
    Ich denke es muss einen tieferen Grund dafür geben.
    Theoretisch müsste das Programm nun mit 100% Auslastung laufen,
    da jeder der Threads nun immer zu rechnen hat.

    Also viele Grüße bb

    rom4o



  • rom4o schrieb:

    Theoretisch müsste das Programm nun mit 100% Auslastung laufen,
    da jeder der Threads nun immer zu rechnen hat.

    Jaja, die Theorie 😉 Kommentier mal die Zeile mit "cout << ..." aus, leider warten die Threads sehr lange auf die Ausgabe.

    edit: Auskommentieren, damit du siehst, dass die Threads immer "lange" Zeit in der Ausgabe hängen.


  • Mod

    BTW: Warum einen langsamen Mutex nutzen wenn es schnelle CriticalSections gibt?



  • @Badestrand: Ich habe ja, wie ich auch schon geschrieben habe, die Ausgabe zum Test herausgenommen. Dann läuft das Programm sehr viel schneller aber trotzdem nur mit halber Auslastung.
    Für aim=200000 und mit 'cout<<prime<<" ";' braucht mein Laptop ca. 8sec.
    Für aim=200000 und ohne cout braucht er nur knapp 1sec.

    @Martin Richter: Könnte sein, dass es daran liegt. Habe in anderen Artikeln auch schon gelesen, dass Mutex´s aufwendig und zeitraubend sind.
    Ich habe leider keine Ahnung wie man Critical Section umgeht.
    Hast du vielleicht ein kurzes Beispiel?

    Vielen Dank euch.

    rom4o



  • Martin Richter schrieb:

    BTW: Warum einen langsamen Mutex nutzen wenn es schnelle CriticalSections gibt?

    Ich vergesse die Critical Sections oft 😞 Bleibt Mutexen eigentlich noch ein anderes Einsatzgebiet als Interprocess-Synchro?

    rom4o schrieb:

    Ich habe leider keine Ahnung wie man Critical Section umgeht.

    http://www.google.de/search?hl=de&q=critical+section&btnG=Google-Suche&meta=


Anmelden zum Antworten