Ich zeichne mittels GDI+ und GdipDrawArc einige Kreisbögen. Mein Ziel ist, so eine ähnliche visuelle Ordnerdarstellung des Dateisystems wie bei Filelight zu bekommen. Im Grunde geht das schon ganz gut, siehe hier:
Da aber die Grafik bei Änderung der Fenstergröße jedes Mal neu gezeichnet wird, ist mir Performance wichtig. Daher dachte ich, ich werf' mal Parallelisierung drauf.
Nun, GDI+ ist prinzipiell threadsicher und muss, laut Doku, für jeden der parallelen Threads initialisiert werden. Das mach' ich zunächst, hole mir dann (wieder single-threaded) ein Handle auf mein DC, stelle Anti-Aliasing ein und zeichne den inneren Kreis. Dies wird immer korrekt ausgeführt. Danach geht's ans Zeichnen der Kreissegmente, und zwar jetzt eben parallel. Ich parallelisiere über die äußere Schleife.
Laut Doku darf man nicht aus mehreren Threads gleichzeitig auf GDI+ zugreifen. Macht man es doch, können meiner Erfahrung nach zwei Probleme auftreten:
1.) GDI+ gibt "ObjectBusy" zurück. Schön, dann versuche ich es eben weiter, bis das Objekt nicht mehr busy ist.
2.) GDI+ kann sich dann auch schonmal "verklemmen", und der Prozess stürzt ab.
Ersteres Problem löse ich mit einer while-Schleife, die versucht, sich immer weiter in die Funktion "reinzuhämmern", so lange, bis es eben klappt. Dies ist aber sicher nicht die feine englische Art. Zweiteres Problem könnte hierdurch ausgelöst werden. Vermute ich zumindest. Ich brauche dafür eine elegantere Lösung als trial-and-error und glaube, dass damit beide Probleme gleichzeitig verschwinden werden.
Hier der entscheidende Codeteil:
Da aber die Grafik bei Änderung der Fenstergröße jedes Mal neu gezeichnet wird, ist mir Performance wichtig. Daher dachte ich, ich werf' mal Parallelisierung drauf.
Nun, GDI+ ist prinzipiell threadsicher und muss, laut Doku, für jeden der parallelen Threads initialisiert werden. Das mach' ich zunächst, hole mir dann (wieder single-threaded) ein Handle auf mein DC, stelle Anti-Aliasing ein und zeichne den inneren Kreis. Dies wird immer korrekt ausgeführt. Danach geht's ans Zeichnen der Kreissegmente, und zwar jetzt eben parallel. Ich parallelisiere über die äußere Schleife.
Laut Doku darf man nicht aus mehreren Threads gleichzeitig auf GDI+ zugreifen. Macht man es doch, können meiner Erfahrung nach zwei Probleme auftreten:
1.) GDI+ gibt "ObjectBusy" zurück. Schön, dann versuche ich es eben weiter, bis das Objekt nicht mehr busy ist.
2.) GDI+ kann sich dann auch schonmal "verklemmen", und der Prozess stürzt ab.
Ersteres Problem löse ich mit einer while-Schleife, die versucht, sich immer weiter in die Funktion "reinzuhämmern", so lange, bis es eben klappt. Dies ist aber sicher nicht die feine englische Art. Zweiteres Problem könnte hierdurch ausgelöst werden. Vermute ich zumindest. Ich brauche dafür eine elegantere Lösung als trial-and-error und glaube, dass damit beide Probleme gleichzeitig verschwinden werden.
Hier der entscheidende Codeteil:
C:
omp_set_num_threads(omp_get_max_threads());
#pragma omp parallel
{ MyStatus = GdiplusStartup(&token, &input, NULL); }
MyStatus = GdipCreateFromHDC(MyDC, &graphics);
MyStatus = GdipSetSmoothingMode(graphics, SmoothingModeAntiAlias8x8);
MyStatus = DLLDrawArc(0, MaxLevel, 1, 0, RadiusPercentage, TreeStruc[CurrentRootIndex].Color, ScaleWidth, graphics);
#pragma omp parallel for private(i) private(j) private(k) private(nBytes) private(Buff) private(Used) private(Percentage) private(RGBArr) private(MyStatus) private(Counter)
for (i = CurrentClassBase; i <= MaxLevel; i++) {
for (j = 0; j < ArrSize; j++) {
if (LocalArr[j].Level == i) {
nBytes = WideCharToMultiByte(CP_ACP, 0, LocalArr[j].FolderName, -1, NULL, 0, NULL, NULL);
Buff = (LPSTR)malloc(nBytes * sizeof(char));
WideCharToMultiByte(CP_ACP, 0, LocalArr[j].FolderName, -1, Buff, nBytes, NULL, NULL);
if (InStr(Buff, CurrentRoot)) {
Used = LocalArr[j].UsedAsParent;
for (k = j; k < ArrSize; k++) {
if (LocalArr[k].ParentID == LocalArr[j].ID & LocalArr[k].UsedAsParent == 0) {
LocalArr[k].UsedAsParent = Used;
if (TotalSize > 0)
Percentage = LocalArr[k].Size / TotalSize;
else
Percentage = 0.0f;
if (Percentage >= SmallestSize) {
if (Used > 1)
Used = 1;
RGBArr[0] = (i / (float)MaxLevel) * 255;
RGBArr[1] = Used * 255;
RGBArr[2] = 128 - Counter;
TreeStruc[k].Color = RGBArr[2] + (RGBArr[1] * 0x100) + (RGBArr[0] * 0x10000);
Counter++;
if (Counter >= 128)
Counter = 0;
Used = Used + Percentage;
do {
MyStatus = DLLDrawArc(i + 1 - CurrentClassBase, MaxLevel, Percentage, Used, RadiusPercentage, TreeStruc[k].Color, ScaleWidth, graphics);
} while (MyStatus != Ok);
}
}
}
}
free(Buff);
}
}
}
Zuletzt bearbeitet: