Kann man einem Thread eine CPU zuordnen??? Bsp. Primberechnung
-
@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.
-
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=
-
Hallo Leute,
so...jetzt haben wirs.
Ich habe auf folgender Seite http://www.kunsmann.de/cpp/critical_section.htm
eine sehr schöne Erkärung zur Critical Section gefunden, es ist auch
viel anderes Interessantes dort zu finden.Ich habe nun in meinem Primzahlenprogramm die Mutex´s durch CriticalSection´s ersetzt.
Das Programm läuft wie gewohnt und nun endlich wie von Martin Richter prophezeit
mit voller Prozessorauslastung. Wunderbar!!!!Endlich...
Das hat sich doch gelohnt.Hier ist das fertige Programm für die, die es interessiert:
// prim_cs_dualcore.cpp #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 timestep = 50; //int aim = 1000; int aim = 10000000; CRITICAL_SECTION csVarInAccess; // Critical Section definieren CRITICAL_SECTION csOutputInAccess; // Critical Section definieren 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; } int getNextCandidate() { EnterCriticalSection(&csVarInAccess); int r=c; c=c+2; LeaveCriticalSection(&csVarInAccess); return r; } void printPrime( int prime ) { EnterCriticalSection(&csOutputInAccess); // cout<<prime<<" "; count++; LeaveCriticalSection(&csOutputInAccess); } DWORD WINAPI ThreadProc1( LPVOID pvoid ) { int cc=getNextCandidate(); while(cc<=aim) { if(Prim(cc)) printPrime(cc); cc=getNextCandidate(); } return 0; } DWORD WINAPI ThreadProc2( LPVOID pvoid ) { int cc=getNextCandidate(); while(cc<=aim) { if(Prim(cc)) printPrime(cc); cc=getNextCandidate(); } return 0; } void main() { InitializeCriticalSection(&csVarInAccess); // Critical Section initialisieren InitializeCriticalSection(&csOutputInAccess); // Critical Section initialisieren GetSystemTime(&systimeold); //take time BEGIN cout << "Thread1 startet..."<<endl; DWORD dwThreadParam1 = 1; HANDLE hThread1 = CreateThread (NULL,0,ThreadProc1,&dwThreadParam1,0,NULL); SetThreadAffinityMask(hThread1, 1); EnterCriticalSection(&csOutputInAccess); cout << "Thread2 startet..."<<endl; LeaveCriticalSection(&csOutputInAccess); 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 <<endl; cout << "Time: " << hDiff << ":" << mDiff << ":" << sDiff << ":" << msDiff << endl; cout << "Anzahl: " << count <<endl; // Thread-Handles schließen CloseHandle( hThread1 ); CloseHandle( hThread2 ); TerminateThread (hThread1, 0); TerminateThread (hThread2, 0); DeleteCriticalSection(&csVarInAccess); // Critical Section löschen DeleteCriticalSection(&csOutputInAccess); // Critical Section löschen }
Die Ausgabe der Primzahlen kann man in Zeile 63 wieder einstellen, jedoch läuft dann
das Programm viel viel langsamer.Ich denke man kann das Programm, auch ohne großen Aufwand, für mehr als 2 Kerne leicht anpassen.
Vielen Dank an Alle die mir hier so hilfreiche Ratschläge gegeben haben.Viele Grüße rom4o
-
und jetzt schmeiß bitte noch die ThreadProc2 weg. kannst beide male die 1 nehmen.
-
Badestrand schrieb:
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?
Ja, wenn man ein Wait mit Timeout braucht. Natürlich kann man sich auch das mit einer CRITICAL_SECTION, einem EVENT und einer Queue selbst stricken, und die selbst gestrickte Version wird immer noch schneller als eine MUTEX sein. Aber oft ist einem das einfach zu umständlich, und mit einer MUTEX geht das eben out of the box.
Und man kann MUTEXen einen Namen geben. An manchen Stellen ist das wichtig. Guck dir z.B. mal die Implementierung von Boost.Thread's "once" für Windows an. Das ist ein klassisches Beispiel für Fälle wo man sich viel Arbeit sparen kann, dadurch dass man solche "named objects" verwendet.
-
@volkard: ja hab ich gemacht, ich habe das ja auch von dir in deiner Vorlage so bekommen. Ich habe nur noch mal 2 einzelne Threads erstellt, weil ich unterschiedliche Sleep()-Werte bei meinen Tests reingeschrieben habe.
danke, bb rom4o