PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : c/c++: suchfunktion erzeugt 100% prozessor-auslastung


tes
30.05.2004, 13:46
hi,

also, ich schreibe seit laengeren an einem reg-suchtool.
und die primaere suchfunktion erzeugt eine 100% auslastung des prozessors.

wenn im hauptfenster die suche ausgeloest wird, erhalte (ich als user) die kontrolle erst wieder, wenn die suche beendet wurde.

welche techniken gibt es um eine funktion ressourcen-schonender auszufuehren und bei bedarf abzubrechen?
hilft mir hier evtl. thread-programmierung weiter?

PuckPoltergeist
30.05.2004, 14:25
Multithreading

mj
31.05.2004, 13:31
Yup, die einzige Lösung ist in dem Fall, die Suche in einen eigenen Thread auszulagern.

PuckPoltergeist
31.05.2004, 15:39
Naja, es geht auch mit nur einem Thread, was aber ziemlich aufwändig wird.

tes
31.05.2004, 18:19
danke fuer die antworten.
beim stichwort multithreading hab ich mich mal eingelesen, und hab jetzt ne kleine testanwendung fertig.
es ist eine winapi-gui, die auf button-click einen thread startet und per button-click beendet.
werd ich demnaechst mal implementieren.

soll ich meinen ersten versuch posten, fuer die allgemeinheit?

PseudoReal
09.06.2004, 18:58
ja zeige mal :)

Exr
09.06.2004, 23:24
Je nachdem welche Software du nimmst kannst du auch einen "Sleep" einbauen. Damit bekommst du zwar nicht die Kontrolle über die Software, jedoch wird die CPU-Last gesenkt. Vorsicht: je nachdem wo du den Sleep einbaust, explodiert deine Laufzeit. Am besten machst du nur 1ms Pause: Sleep(1).

Die Alternative mit dem Thread ist so glücklich auch nicht: dann zieht der separate Thread eben 100% Systemlast.

WEnn du unter Windows programmierst hast du zwei schöne Möglichkeiten:

1.) Du senkst die Priorität des Programms. Das ist nicht soo einfach, aber die beste Möglichkeit. Im Prinzip hast du damit erreicht, was ein separater Thread dir auch ermöglicht hätte. Dort kannst du die Prio beim Erstellen auch angeben. Um die Prio der Hauptanwendung zu senken, brauchst du als erstes einen Handle auf dessen Thread. Mittels diesem kannst du dann über eine Systemfunktion die Prio senken.

2.) Bei Borland gibt es den Aufruf "Application->ProcessMessages();". Damit führt das Programm User-getriggerte Befehle aus. Ob es das bei MS auch gibt (nehm ich mal an) und wie das heisst, weiss ich leider nicht.

Aber mit den letzten beiden Möglichkeiten müsstest du auch hinkommen.

TiKu
09.06.2004, 23:45
Original geschrieben von Exr
2.) Bei Borland gibt es den Aufruf "Application->ProcessMessages();". Damit führt das Programm User-getriggerte Befehle aus. Ob es das bei MS auch gibt (nehm ich mal an) und wie das heisst, weiss ich leider nicht.Bei VB heißt es DoEvents. Bei C/C++ gibt's für sowas glaube ich ein Verfahren namens Message-Pumping.

Exr
09.06.2004, 23:48
Application->ProcessMesages() ist aus Borland C++Builder.
Bei Borland kanns aber schon sein dass die das von der Pascal-Seite her benannt haben...

gn8,
exr

Heretic
10.06.2004, 09:58
Original geschrieben von Exr
Am besten machst du nur 1ms Pause: Sleep(1).

Dummerweise kann windows das nicht so genau. Die Maximale Genauigkeit liegt bei 10 ms .... Sleep(1) und Sleep(10) haben also genau des gleichen Effekt: 10 ms "Schlaf"

Exr
10.06.2004, 22:49
Wow. Danke. Wusste ich nicht. Je nach Anwendung wird das echt zum Killer.... *grübel*

Eigentlich ist der "Sleep" auch recht doof. Aber immer noch besser als 100% CPU-Last wenns nicht wirklich dringend ist.

exr

Novox
11.06.2004, 18:25
Original geschrieben von Exr
Die Alternative mit dem Thread ist so glücklich auch nicht: dann zieht der separate Thread eben 100% Systemlast.

Wenn ich seine Frage richtig verstanden habe, geht’s ihm wohl weniger darum, die Systemauslastung (die ja im Sinne einer möglichst schnellen Suche durchaus wünschenswerterweise bei 100% liegen sollte) zu senken. Er will die Reaktivität der GUI und des restlichen Systems gewährleisten. Da sollten zwei separate Threads (Such-Thread mit niedrigerer Priorität, GUI-Thread mit normaler Priorität) effizienter sein, als n*10 ms Zwangspause. Bei einer single-threaded Lösung, bei der nur der Haupt-Thread mit niedrigerer Priorität läuft, reagiert zwar Windows besser. Das ändert aber nichts daran, daß die programmeigene GUI weiterhin nicht oder nur träge reagiert.
Also:
Quick and Dirty: Sleep(n);
Sauber und effizient: hThread = CreateThread(...);

Ray
11.06.2004, 20:01
Es geht aber auch mit der kooperativen Methode, wie es z.B. unter Win16 üblich war und bei vielen kooperativen Betriebssystemen im embedded Bereich teilweise immer noch ist.

Unter Win32 mit C in etwa so im main() Teil der Anwendung:



RunCount = 0;
while (ProgramRunning)
{
if (!PeekMessage( &msg,0,0,0,PM_REMOVE))
{
// Keine Nachricht in der Queue, ein paar Searches durchführen.
if (++RunCount < RUN_COUNT_MAX)
{
SearchOnePart();
continue;
}
}
RunCount = 0;

// Standard Windows-Nachrichtenschleife:
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

Die Suchfunktion muß halt aufgebrochen sein, d.h. mit jedem Aufruf ein Stück weitersuchen.
Wieviel SearchOnePart() genau macht, muß ermittelt werden, genauso der Wert von RUN_COUNT_MAX.
Dann lässt sich das Ganze so tunen, dass System und Anwendung bedienbar bleiben.

Ciao,
Ray

TiKu
11.06.2004, 20:06
Das ist meines Wissens das, was man als Message Pumping bezeichnet.

Ray
11.06.2004, 20:36
Original geschrieben von TiKu
Das ist meines Wissens das, was man als Message Pumping bezeichnet.
Stimmt. ;)
Solchen Code hab ich Jahre bevor mir der Begriff "Message Pumping" übern Weg lief geschrieben. Bin vorhin über ein Stück altes Programm gestolpert, weshalb ich's auch gepostet habe.
An für sich dürfte man mit der Threading-Methode besser fahren und muß dabei vor allem seinen Algorithmus nicht künstlich aufbrechen. Gut ist aber, beide Verfahren zu kennen, für den Fall, dass Threading nicht zur Verfügung steht.

@TiKu: Man erkennt Dich ja kaum wieder... *buck*

tes
13.06.2004, 13:45
oh, hier tut sich ja noch was. :)

fuer PseudoReal:

ich hab den about-dlg einer hallo welt win32-anw missbraucht (vc++6).
3x buttons (IDC_START, IDC_END, IDOK)
1x edit (IDC_STATUS)
1x static (IDC_DESCR)
1x combobox (IDC_REFRESH) typ: dropdown


// thread_test.cpp : Definiert den Einsprungpunkt für die Anwendung.
//

#include "stdafx.h"
#include "resource.h"
#include <stdio.h>
#include <windows.h> //CreateThread()

#define RSTRING "thread running "

HINSTANCE hDlgInstance;
BOOL repeat = TRUE; //globaler stopflag
BOOL running = FALSE; //globaler runningflag

LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);

void initComponents(HWND);
DWORD CBIndex2Refresh(HWND);

void startThread(HWND);
unsigned long __stdcall checkRepeat(void*);
void endThread();

//////////////////////////////////////////////////////////////////////////////////////////
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
hDlgInstance = hInstance;
DialogBox(hDlgInstance, (LPCTSTR)IDD_ABOUTBOX, NULL, (DLGPROC)About);

return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_INITDIALOG:
initComponents(hDlg);
return TRUE;

case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDOK:
case IDCANCEL:
if(running)
{
//stopflag setzen
endThread();
//warte bis wirklich die threadzeit abgelaufen ist
Sleep( (CBIndex2Refresh(hDlg)+1) );
}
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
break;

case IDC_START:
{
//thread erzeugen und starten
startThread(hDlg);
}
break;

case IDC_END:
{
//thread beenden
endThread();
}
break;
}
}
return FALSE;
}

//////////////////////////////////////////////////////////////////////////////////////////
void initComponents(HWND hParent)
{
//fenster-titel
SetWindowText(hParent, "ThreadTest");

//textfelder
SetDlgItemText(hParent, IDC_STATUS, "current thread status");
SetDlgItemText(hParent, IDC_DESCR, "refresh time:");

//buttons
SetDlgItemText(hParent, IDC_START, "start thread");
SetDlgItemText(hParent, IDC_END, "end thread");
SetDlgItemText(hParent, IDOK, "close");

//combobox
SendDlgItemMessage(hParent, IDC_REFRESH, CB_ADDSTRING, 0, (LPARAM)"0,1 sec");
SendDlgItemMessage(hParent, IDC_REFRESH, CB_ADDSTRING, 0, (LPARAM)"0,3 sec");
SendDlgItemMessage(hParent, IDC_REFRESH, CB_ADDSTRING, 0, (LPARAM)"0,5 sec");
SendDlgItemMessage(hParent, IDC_REFRESH, CB_ADDSTRING, 0, (LPARAM)"1,0 sec");
SendDlgItemMessage(hParent, IDC_REFRESH, CB_ADDSTRING, 0, (LPARAM)"1,5 sec");
SendDlgItemMessage(hParent, IDC_REFRESH, CB_ADDSTRING, 0, (LPARAM)"2,0 sec");
//default: nach erzeugen, den 3ten markieren
SendDlgItemMessage(hParent, IDC_REFRESH, CB_SETCURSEL, WPARAM(2), 0);

}

//////////////////////////////////////////////////////////////////////////////////////////
DWORD CBIndex2Refresh(HWND hParent)
{
int cbIndex;

cbIndex = SendDlgItemMessage(hParent, IDC_REFRESH, CB_GETCURSEL, 0, 0);
switch(cbIndex)
{
case 0:
return(100L);//millisekunden
case 1:
return(300L);
default:
case 2:
return(500L);//default auswahl
case 3:
return(1000L);
case 4:
return(1500L);
case 5:
return(2000L);
}
return(NULL);
}

//////////////////////////////////////////////////////////////////////////////////////////
void startThread(HWND hParent)
{
HANDLE hMyThread;
DWORD id;

if(!running)
{
repeat = TRUE;
hMyThread = CreateThread(NULL, 0, checkRepeat, hParent, 0, &id);
}
}

//////////////////////////////////////////////////////////////////////////////////////////
unsigned long __stdcall checkRepeat(void *hParent)
{
char out[18];
char *points[6]={"",".","..","..."," .."," ."};
int pos = 0;

running = TRUE;

while(repeat)
{


Sleep(CBIndex2Refresh((HWND)hParent));
sprintf(out, "%s%s", RSTRING, points[pos]);
if(pos == 5)
pos=0;
else
pos++;
SetDlgItemText((HWND)hParent, IDC_STATUS, out);
}

running = FALSE;
SetDlgItemText((HWND)hParent, IDC_STATUS, "thread stopped");

return(0);//dummy-ret
}

//////////////////////////////////////////////////////////////////////////////////////////
void endThread()
{
repeat = FALSE;
}


wie einige vorgeschlagen haben, werd ich das ganze mit zwei threads verwirklichen.
einen control-thread, der einen worker-thread startet/beendet.
wie einige versuche zeigten, bringt ein sleep im worker-thread eine deutlich geringere prozessorlast und andere evtl. laufende anwendungen bekommen auch noch ein bisserl rechenzeit ab.

ich hatte auch schon an ein eingrenzen der suche auf eine bestimmte anzahl von ergebnissen gedacht, und bei "nichts tun" um die anzahl weiter fortgesetzt wird.
aber dafuer muesst ich die suche neu schreiben, was mir jetzt zu aufwaendig erscheint.
zudem muesst ich mir einige variablen merken, damit ich die suche fortgesetzen kann.
ich glaub mit threads fahr ich besser.

ich danke fuer die rege anteilnahme. :)

athomi
14.10.2004, 20:57
Hi,

ich habe ein Thread erzeugt, mit dem Glauben, dass ich so die 100% CPU Auslastung vermeiden kann. Ich dachte, dass eine Endlosschleife in einem Thread die CPU nicht sehr auslastet, was sie ansonsten eben tut. Nun, ich habe mich geirrt. Im Grunde ist das irgendwie logisch aber ich habe es mit eingenen Augen gesehen, dass es nicht so sein muss. Es handelt sich um ein borland C++ Programm, was so ähnlich funktioniert wie mein Progeamm aber viel mehr Funktionen hat und mehr tut, aber eben nur mit ca. 5% die CPU auslastet.

Ich Programmiere mir VC 6.0 und vorerst nur in WinAPI.

Gibt es da ein Weg? In dem Programm gibt es auch ein sleep(1) aber bei meinem Programm macht das kein Unterschied.

In einem Tutorial habe ich in dem Kappitel über Threads gelesen, dass eine Thread Funktion niemals explizit aufgeruffen werden darf, was ist damit gemeint?

MfG,

Athomi

tes
14.10.2004, 23:05
hi athomi,

nach meinen erfahrungen, zieht ein thread auch volle cpu-auslastung.
aber man hat die moeglichkeit, einen thread mit geringerer prioritaet zu starten(siehe function SetThreadPriority() http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/setthreadpriority.asp (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/setthreadpriority.asp) ).
soll die rechenaufwaendige berechnung bis zum ende durchgefuehrt werden, reicht eigentlich ein thread mit geringer prio oder halt der sleep.

EDIT: hier hab ich mich verzettelt, man kann natuerlich auch einen einzelnen thread beenden.
das beweist ja die testanwendung.

ich probiere derzeit eine zweite moeglichkeit aus.
die rechenaufwaendige berechnung lass ich in einer nicht sichtbaren konsolen-anwendung laufen.
das hat auch den vorteil, das ich bei veraenderungen der berechnungsroutine nur die konsolen-anwendung austauschen brauch und die gui kann bleiben wie sie ist.
zudem biete ich dem user die moeglichkeit, die suche auch per commandline ohne gui zu starten.
auch hier hat man die moeglichkeit, die prio der konsolenanwendung festzulegen und vorzeitig zu beenden.
im prinzip ist es das selbe wie mit einem thread.
ob es geschwindigkeitsmaessig etwas bringt, weiss ich noch nicht.
aber die oben genannten vorteile sprechen fuer sich

die frage des expliziten aufrufs kann ich so nicht beantworten.
es ist nicht genau ersichtlich in welchen zusammenhang das gemeint ist.
vorstellen koennt ich mir, das eine funktion, die bereits in einem thread laeuft, nicht zur laufzeit des threads ein weiteres mal aufgerufen werden darf (prozedural gesehen).
dazu koennen sich sicher die anderen aeussern.

gruss tes

athomi
15.10.2004, 14:44
Hi,

vielen Dank für die ausführliche Antwort.

Die Frage der Priorität meines Threads wird mein Problem nicht lösen und eine Konsolenanwendung läuft auch fast immer mit 100% CPU Auslastung, zumindest bei mir da auf jeden Fall eine Dauerschleife läuft.
Mein thread rettet mich in so fern, da ich meine GUI problemlos benutzen kann und ich habe festgestellt, dass wenn ich meine Routine mit SetTimer alles 30 ms starte, ich so die CPU Auslastung auch ca 30% reduzieren kann.
Wenn ich eine Lösung habe werde ich sie im diesem Forum vorstellen.

MfG,

Athomi

tes
15.10.2004, 16:03
hi athomi,

naja, bei mir ist es ja wuenschenswert, das die suche mit vollem power laeuft.
sie soll ja so schnell wie moeglich fertig sein.
ein heruntersetzen der prio bringt bei mir den vorteil, das der user auch gleichzeitig noch andere programme bedienen kann.
die meisten programme werden ja mit NORMAL_PRIORITY_CLASS, bzw THREAD_PRIORITY_NORMAL fuer threads, gestartet.
da meines eine niedrigere prio hat, bekommt es die restliche cpu-power ab, solang eine andere anwendung rechenzeit fuer sich beansprucht.

einen sleep hatte ich auch ausprobiert, aber da war mir die suchdauer dann doch ein bisserl arg lang.
ich parse ja jeden key, namen und wert der registry auf vorkommen eines suchstrings.
da die registry mit der zeit auf mehrere mb im zweistelligen bereich anschwellen kann,
siehst du mit welchem datenaufwand ich beschaeftigt bin bzw die cpu, hehe.
da kam wirklich kein sleep in frage.

der entwickler muss halt entscheiden, was fuer ihn wichtig ist.

und wofuer willst du eine loesung posten? eine endlosschleife zieht immer max. rechenkraft, ausser du verzoegerst sie mit einem timer.

gruss tes



Copyright © 1999 - 2011 Planet 3DNow!
Rechtliche Hinweise