Autor Beitrag
hui1991
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 433

Windows XP, WIndows Vista
Turbo Delphi Explorer| Delphi, PHP,Blitzbasic
BeitragVerfasst: Di 02.12.08 21:32 
Hallo,

wie in der ShoutBox geschrieben hab ich paar Probleme mit Threads.
Ich will eine Single-Thread Funktion auf 2 Threads aufteilen, aber so das die Rechenleistung bei einem Dual-Core höher ist als bei einem Single-Core. Genau gesagt teile ich die Threads auf. Da zwischen durch eine Synchronisation durchgeführt werden soll, weil beide Threads arbeiten mit den selben Daten, wartet der andere Thread so lange bis er fertig ist die Daten zu kopieren. Ist er fertig arbeiten wieder beide Threads parallel.
So weit funktioniert das ja.
Wenn ich aber in TaskManager schaue dann sehe ich nur das ein Core arbeitet.
Anscheinend ist die meiste Arbeit bei den Teilen zu erledigen wo die Threads nicht Parallel laufen. Wobei nein, kann nicht sein, weil Thread 2 auf Core 2 läuft. Also müsste der 2. Core auf volllast sein während der 2. Thread die Daten kopiert.

(Das berechnen ging so schnell, das es nicht angezeigt wurde, das nur ein Core benutzt wurde lag daran, dass das StringGrid befüllen die Leistung gebraucht hat.)
Denke es liegt an einem anderen Problem.

Hier mal mein SourceCode:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
250:
251:
252:
253:
254:
255:
256:
257:
258:
259:
260:
261:
262:
263:
264:
265:
266:
267:
268:
269:
270:
271:
272:
273:
274:
275:
276:
277:
278:
279:
280:
281:
282:
283:
284:
285:
286:
287:
288:
289:
290:
291:
292:
293:
294:
295:
296:
297:
298:
299:
300:
301:
302:
303:
304:
305:
306:
307:
308:
309:
310:
311:
312:
313:
314:
315:
316:
317:
318:
319:
320:
321:
322:
323:
324:
325:
326:
327:
328:
329:
330:
331:
332:
333:
334:
335:
336:
337:
338:
339:
340:
341:
342:
343:
344:
345:
346:
347:
348:
349:
350:
351:
352:
353:
354:
355:
356:
357:
358:
359:
360:
361:
362:
363:
364:
365:
366:
367:
368:
369:
370:
371:
372:
373:
374:
375:
376:
377:
378:
379:
380:
381:
382:
383:
384:
385:
386:
387:
388:
389:
390:
391:
392:
393:
394:
395:
396:
397:
398:
399:
400:
401:
402:
403:
404:
405:
406:
407:
408:
409:
410:
411:
412:
413:
414:
415:
416:
417:
418:
419:
420:
421:
422:
423:
424:
425:
426:
427:
428:
429:
430:
431:
432:
433:
434:
435:
436:
437:
438:
439:
440:
441:
442:
443:
444:
445:
446:
447:
448:
449:
450:
451:
452:
453:
454:
455:
456:
457:
458:
459:
460:
461:
462:
463:
464:
465:
466:
467:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Grids;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    Button1: TButton;
    StringGrid1: TStringGrid;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

type
  TThreadParams = packed record
    Number: Integer;
  end;
  PThreadParams = ^TThreadParams;

type
  TThreadWork = record
    willstart: array[1..2of boolean; //auf true setzen vor dem waitingpoint
    waiting: array[1..2of boolean; // false: Thread darf bei wartepunkt weiter
                                    // true: Thread muss warten bis wieder false
    exit: array[1..2of boolean; // Wenn beendet ist sollte der andere Thread nicht ewig warten
    locked: boolean;
    n: Integer; //groese der Matrix
    matrix: array of array of Integer;
    reihenfolge1, reihenfolge2: array of Integer;
    fs: TFileStream;
  end;

const
  THREAD_TERMINATE = $0001;
  THREAD_SUSPEND_RESUME = $0002;
  THREAD_GET_CONTEXT = $0008;
  THREAD_SET_CONTEXT = $0010;
  THREAD_SET_INFORMATION = $0020;
  THREAD_QUERY_INFORMATION = $0040;
  THREAD_SET_THREAD_TOKEN = $0080;
  THREAD_IMPERSONATE = $0100;
  THREAD_DIRECT_IMPERSONATION = $0200;
  THREAD_SET_LIMITED_INFORMATION = $0400;
  THREAD_QUERY_LIMITED_INFORMATION = $0800;
  THREAD_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED or SYNCHRONIZE or $03FF;

var
  Form1: TForm1;

  //Thread-Variablen
  ThreadWork: TThreadWork;

implementation

{$R *.dfm}

function OpenThread(dwDesiredAccess: DWord;
  bInheritHandle: Bool;
  dwThreadId: DWord): DWord; stdcallexternal 'kernel32.dll';

function SetThreadAffinityMaskByID(ID, AffinityMask: Cardinal): Boolean;
var
  Handle: THandle;
begin
  Result := False;
  Handle := OpenThread(THREAD_SET_INFORMATION or THREAD_QUERY_INFORMATION, False, ID);
  if Handle <> 0 then begin
    Result := SetThreadAffinityMask(Handle, AffinityMask) <> 0;
    CloseHandle(Handle);
  end;
end;

function Thread1: Integer;
  procedure Exclusive(ThreadNumber: Integer);
  begin
      //Beide auf wollen starten setzen
    ThreadWork.willstart[ThreadNumber] := true;

    //Überprüfen ob schon geschlossen
    while ThreadWork.locked do begin
      if (ThreadWork.willstart[1]) and (ThreadWork.willstart[2]) then
        break;
    end;

    //Egal ob Thread 2 auch starten will, Thread 1 hat vorrang
    ThreadWork.locked := true;
    ThreadWork.willstart[ThreadNumber] := false;
  end;

  procedure Waiting(ThreadNumber: Integer);
  begin
    while ThreadWork.waiting[ThreadNumber] do begin

    end;
  end;
const
  ThreadNumber: Integer = 1;
var
  input: string;
  x, y, z: Integer;
  reihenfolge: array of Integer;
  standardmatrix: array of array of Integer;
  summe: byte;
begin
  try
  //Startkommando festlegen
    ThreadWork.willstart[ThreadNumber] := true;

  //Auf Exclusive schalten
    Exclusive(ThreadNumber);

  //StandardArray größe festlegen
    setlength(ThreadWOrk.reihenfolge1, ThreadWork.n);
    setlength(ThreadWOrk.reihenfolge2, ThreadWork.n);
    setlength(ThreadWork.matrix, ThreadWork.n);
    for x := 0 to ThreadWork.n - 1 do
      setlength(ThreadWOrk.matrix[x], ThreadWork.n);

  //Exclusiveschaltung ausschalten
    ThreadWork.locked := false;

  //Bei nächsten Wartepunkt Thread 2 sagen das er dort warten soll
    ThreadWork.waiting[2] := true;

  //Start der Berechnung der StandardMatrix
    y := 0;
    while y < ThreadWork.n do begin
      x := y;
      for z := 0 to ThreadWork.n - 1 do begin
        inc(x);
        if x > ThreadWork.n then
          x := 1;
        ThreadWork.matrix[y][z] := x;
      end;
      inc(y, 2);
    end;

  //Berechnen des ersten Array
    setlength(reihenfolge, ThreadWork.n);
    for x := 1 to ThreadWork.n do begin
      reihenfolge[x - 1] := x;
    end;
    for z := ThreadWork.n downto 1 do begin
      x := random(ThreadWork.n) + 1;
      while reihenfolge[x - 1] = 0 do begin
        inc(x);
      end;
      ThreadWork.reihenfolge1[ThreadWork.n - z] := reihenfolge[x - 1];
    end;

  //Wartepunkt
    while not ThreadWork.willstart[2do begin

    end;

  //Anderes Programm weiterlaufen lassen
    ThreadWork.willstart[2] := false;
    ThreadWork.waiting[2] := false;

  //Kopieren des Standardgrids
  //Startkommando festlegen
    ThreadWork.willstart[ThreadNumber] := true;

  //Größe festlegen
    setlength(standardmatrix, ThreadWork.n);
    for y := 0 to THreadWork.n - 1 do begin
      setlength(standardmatrix[y], ThreadWork.n);
    end;

  //Auf Exclusive schalten
    Exclusive(ThreadNumber);

  //Kopieren
    for x := 0 to ThreadWork.n - 1 do begin
      for y := 0 to ThreadWork.n - 1 do begin
        standardmatrix[x][y] := ThreadWork.matrix[x][y];
      end;
    end;

  //Sperre aufheben
    Threadwork.locked := false;

  //Bei nächsten Wartepunkt Thread 2 sagen das er dort warten soll
    ThreadWork.waiting[2] := true;

  //Zeilen tauschen
    y := 0;
    while y < ThreadWork.n do begin
      for x := 0 to ThreadWork.n - 1 do begin
        ThreadWork.matrix[ThreadWork.reihenfolge1[y] - 1][x] := standardmatrix[y][x];
      end;
      inc(y, 2);
    end;

  //Wartepunkt
    while not ThreadWork.willstart[2do begin

    end;

  //Anderes Programm weiterlaufen lassen
    ThreadWork.willstart[2] := false;
    ThreadWork.waiting[2] := false;

  //Auf Exclusive schalten
    Exclusive(ThreadNumber);

  //Kopieren
    for x := 0 to ThreadWork.n - 1 do begin
      for y := 0 to ThreadWork.n - 1 do begin
        standardmatrix[x][y] := ThreadWork.matrix[x][y];
      end;
    end;

  //Sperre aufheben
    Threadwork.locked := false;

  //Spalten tauschen
    x := 0;
    while x < ThreadWork.n do begin
      for y := 0 to ThreadWork.n - 1 do begin
        ThreadWork.matrix[y][ThreadWork.reihenfolge2[x] - 1] := standardmatrix[y][x];
      end;
      inc(x, 2);
    end;

  //Thread beenden
  finally
    ThreadWork.exit[ThreadNumber] := true;
  end;
end;

function Thread2: Integer;
  procedure Exclusive(ThreadNumber: Integer);
  begin
    //Beide auf wollen starten setzen
    ThreadWork.willstart[ThreadNumber] := true;

    //Überprüfen ob schon geschlossen
    while ThreadWork.locked do begin

    end;

    //Wenn nicht geschlossen überprüfen ob 1 starten will
    if ThreadWork.willstart[1then begin
      //So lange warten bis 1 fertig ist
      while ThreadWork.willstart[1or ThreadWork.locked do begin

      end;
    end;

    //Jetzt wieder schließen
    ThreadWork.locked := true;
    ThreadWork.willstart[ThreadNumber] := false;
  end;

  procedure Waiting(ThreadNumber: Integer);
  begin
    while ThreadWork.waiting[ThreadNumber] do begin

    end;
  end;
const
  ThreadNumber: Integer = 2;
var
  input: string;
  x, y, summe, z: Integer;
  standardmatrix: array of array of Integer;
  reihenfolge: array of Integer;
begin
  try
  //Startkommando festlegen
    ThreadWork.willstart[ThreadNumber] := true;

  //Exclusiven zutritt
    Exclusive(ThreadNumber);

  //Start der Berechnung der StandardMatrix
    y := 1;
    while y < ThreadWork.n do begin
      x := y;
      for z := 0 to ThreadWork.n - 1 do begin

        inc(x);
        if x > ThreadWork.n then
          x := 1;
        ThreadWork.matrix[y][z] := x;
      end;
      inc(y, 2);
    end;

  //Berechnen des zweiten Array
    setlength(reihenfolge, ThreadWork.n);
    for x := 1 to ThreadWork.n do begin
      reihenfolge[x - 1] := x;
    end;
    for z := ThreadWork.n downto 1 do begin
      x := random(ThreadWork.n) + 1;
      while reihenfolge[x - 1] = 0 do begin
        inc(x);
      end;
      ThreadWork.reihenfolge2[ThreadWork.n - z] := reihenfolge[x - 1];
    end;

  //Wartepunkt
    ThreadWork.willstart[ThreadNumber] := true;
    Waiting(ThreadNumber);

  //Kopieren des Standardgrids
  //Startkommando festlegen
    ThreadWork.willstart[ThreadNumber] := true;

  //Größe festlegen
    setlength(standardmatrix, ThreadWork.n);
    for y := 0 to THreadWork.n - 1 do begin
      setlength(standardmatrix[y], ThreadWork.n);
    end;

  //Auf Exclusive schalten
    Exclusive(ThreadNumber);

  //Kopieren
    for x := 0 to ThreadWork.n - 1 do begin
      for y := 0 to ThreadWork.n - 1 do begin
        standardmatrix[x][y] := ThreadWork.matrix[x][y];
      end;
    end;

  //Sperre aufheben
    Threadwork.locked := false;

  //Zeilen tauschen
    y := 1;
    while y < ThreadWork.n do begin
      for x := 0 to ThreadWork.n - 1 do begin
        ThreadWork.matrix[ThreadWork.reihenfolge1[y] - 1][x] := standardmatrix[y][x];
      end;
      inc(y, 2);
    end;

  //Wartepunkt
    ThreadWork.willstart[ThreadNumber] := true;
    Waiting(ThreadNumber);

  //Auf Exclusive schalten
    Exclusive(ThreadNumber);

  //Kopieren
    for x := 0 to ThreadWork.n - 1 do begin
      for y := 0 to ThreadWork.n - 1 do begin
        standardmatrix[x][y] := ThreadWork.matrix[x][y];
      end;
    end;

  //Sperre aufheben
    Threadwork.locked := false;

  //Spalten tauschen
    x := 1;
    while x < ThreadWork.n do begin
      for y := 0 to ThreadWork.n - 1 do begin
        ThreadWork.matrix[y][ThreadWork.reihenfolge2[x] - 1] := standardmatrix[y][x];
      end;
      inc(x, 2);
    end;

  //Thread beenden
  finally
    ThreadWork.exit[ThreadNumber] := true;
  end;
end;

function ThreadFunc(tp: PThreadParams): Integer;
var
  Number: Integer;
  s: string;
begin
  sleep(1000);
  Number := PThreadParams(tp)^.Number;

  if Number = 1 then begin
    Thread1;
  end;
  if Number = 2 then begin
    Thread2;
  end;
end;

procedure RunDualThread;
const
  Moeglichkeiten: array[0..4of Char = ('Q''O''I''S''A');
var
  tp1, tp2: PThreadParams;
  Thread1, Thread2: THandle;
  ThreadID1, ThreadID2: Cardinal;
  erg: string;
  x, y: Integer;
begin
  // Speicher für Struktur reservieren.
  New(tp1);
  New(tp2);

  // Daten den feldern der Struktur zuweisen.
  tp1.Number := 1;
  tp2.Number := 2;

  // Controls deaktivieren
  Form1.Button1.Enabled := false;

  // Mit Daten füllen
  ThreadWork.willstart[1] := false;
  ThreadWork.willstart[2] := false;
  ThreadWork.waiting[1] := false;
  ThreadWork.waiting[2] := false;
  ThreadWork.locked := false;
  ThreadWork.n := 1500;
  Form1.StringGrid1.RowCount := ThreadWork.n;
  Form1.StringGrid1.ColCount := ThreadWork.n;

  // Thread 1 erzeugen.
  Thread1 := BeginThread(nil0, @ThreadFunc, tp1, 0, ThreadID1);

//  sleep(10);

  // Thread 2 erzeugen.
  Thread2 := BeginThread(nil0, @ThreadFunc, tp2, 0, ThreadID2);

  //Kernverteilung
  //SetThreadAffinityMaskByID(GetCurrentThreadID, 3); // HauptThread auf prozessor core3 setzen
  SetThreadAffinityMaskByID(ThreadID1, 1); // WorkThread1 auf prozessor core1 setzen
  SetThreadAffinityMaskByID(ThreadID2, 2); // WorkThread2 auf prozessor core2 setzen


  // Auf Beendigung des Threads warten.
  WaitForSingleObject(Thread1, INFINITE);
  // Auf Beendigung des Threads warten.
  WaitForSingleObject(Thread2, INFINITE);

  //Ausgabe
  for x := 0 to ThreadWork.n - 1 do begin
    for y := 0 to ThreadWork.n - 1 do begin
      Form1.StringGrid1.Cells[x, y] := IntToStr(ThreadWork.Matrix[x, y]);
    end;
  end;

  //Dispose
  Dispose(tp1);
  Dispose(tp2);

  //Controls aktivieren
  Form1.Button1.Enabled := true;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  RunDualThread;
end;

end.


Ja ich weiß sind 500 Zeilen und auch ziemlich viel.
Wenn AV ist dann stürtzt ein Thread ab und der andere bleibt auf der Warteschleife hocken. (wie man sieht ist Exit dafür gedacht dies zu beheben).

Irgendwas mache ich falsch, ich hab ein QuadCore deswegen hab ich Core 1-4 (oder 0-3).
Den rest den ich schreiben wollte, hab ich vergessen, aber das wichtigste steht ja schonmal.

Edit://
Mir ist gerade aufgefallen, dass das Programm ja schon den zweiten Core benutzt.
Dann fällt meine erste Frage weg, was mich aber trotzdem wundert das manchmal ein AV kommt und wenn ich debugge das er nicht da ist.
AV kommen doch nur, wenn Thread1 und Thread2 gleichzeitig schreiben wollen oder?
Das gilt aber nicht für Array oder?

MfG
hui1991