Autor Beitrag
Sauger Chris
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 228

Win XP, Linux SuSE 9.2
Delphi 4,Delphi 7 Ent.
BeitragVerfasst: Mi 22.10.08 17:07 
Moin

und zwar versuche ich mich gerade an dem gebiet Threads

aber ich steig da noch nicht wirklich dahinter :-(

könnte mir mal einer einen source posten wo man sieht wie eine listbox mit hilfe von Threads geladen wird
also einfach eine txt laden und die lines adden


würde mir sehr beim verstehen von threads helfen ich bedanke mich schon mal =)



mfg euer chris
j.klugmann
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mi 22.10.08 17:18 
Guckst du hier:www.delphi-library.d...t=threads%20tutorial
Dann du wissen.
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Mi 22.10.08 17:50 
VCL ist nicht thread-safe. Du darfst den Inhalt einer Listbox in einem Thread nicht ändern.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 22.10.08 18:22 
Doch, aber du musst den Zugriff synchronisieren.

Erstelle einmal mit Datei --> Neu --> Delphi Dateien --> Thread Objekt (oder so ähnlich je nach Delphiversion) ein neues Threadgerüst, dann siehst du dort auch ein Beispiel für den Zugriff auf die VCL.
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Mi 22.10.08 20:30 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Doch, aber du musst den Zugriff synchronisieren.

Synchronisierte Methodenaufrufe werden in der Hauptschleife des Hauptthreads ausgeführt bzw. abgearbeitet. Die Methode läuft nicht im Thread, aus welche sie aufgerufen wird.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 22.10.08 20:32 
Richtig, aber bei dir hörte es sich so an als ob es gar nicht ginge, wenn man in einem Thread ist, das meinte ich ;-). Dass das im Kontext des Hauptthreads ausgeführt wird, ist natürlich richtig.
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Mi 22.10.08 20:35 
Kommt halt darauf an, was er genau erreichen will. Geschwindigkeitstechnisch wird es wohl kaum Sinn machen. Weder wenn er LoadFromFile synchronisiert aufruft noch wenn er jeden Aufruf von Lines.Add synchronisiert.

@Sauger Chris: Willst du die Threads einfach anhand eines Beispiels verstehen - was erhoffst du dir vom Gebrauch von Threads?
Yogu
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2598
Erhaltene Danke: 156

Ubuntu 13.04, Win 7
C# (VS 2013)
BeitragVerfasst: Mi 22.10.08 20:42 
Wenn du dich einfach mal ein wenig mit Threads beschäftigen willst, würde ich dir einen Download per Indys empfehlen - das ist immer wieder ganz nützlich. Eine weitere Anwendungsmöglichkeit wäre, Dateiinfos auszulesen und in Listen speichern, die später von Anzeigekomponenten verwendet werden.
Sauger Chris Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 228

Win XP, Linux SuSE 9.2
Delphi 4,Delphi 7 Ent.
BeitragVerfasst: Do 23.10.08 14:50 
@delfiphan

wen möglich würde ich gern per threads das laden von meiner listbox beschleunigen wen das nicht möglich ist
wenigstens das einfrieren des Main programmes wärend dem ladevorgang zu umgehen :)

und ja ich möchte anhand von beispielen die thread programmierung besser verstehen
speziel einfach mal ne datei in ne listbox , Memo oder sonst was laden würde mir halt leichter fallen =)


@Yogu

haste zufällig gute und leicht zu verstehende beispiele zur hand ??


ps. wen ich den source vor mir hab fällt mir das verstehen und arbeiten des threads leichter
wär nett wen ihr mir da bissle unter die arme greifen könntet mittels source beispielen =)


danke schon mal

chris
DeddyH
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Do 23.10.08 14:54 
BeginUpdate und EndUpdate setzt Du aber ein? Wenn nicht, sollte das das Laden der Listbox auch ohne Threads enorm beschleunigen.
Yogu
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2598
Erhaltene Danke: 156

Ubuntu 13.04, Win 7
C# (VS 2013)
BeitragVerfasst: Do 23.10.08 18:57 
user profile iconDeddyH hat folgendes geschrieben Zum zitierten Posting springen:
BeginUpdate und EndUpdate setzt Du aber ein? Wenn nicht, sollte das das Laden der Listbox auch ohne Threads enorm beschleunigen.

Es geht ihm wohl nicht darum, irgendeinen Code zu optimieren, sondern die Handhabung mit Threads zu begreifen und zu üben. ;)



user profile iconSauger Chris hat folgendes geschrieben Zum zitierten Posting springen:
haste zufällig gute und leicht zu verstehende beispiele zur hand ??

Das einzige veröffentliche Projekt, in dem ich Threads verwende, ist AudioPlayer. Die Unit AudioLibraryExt kümmert sich um das Einlesen der Audioinfos wie zum Beispiel ID3-Tags. Da das eine zeitaufwändige Prozedur ist, habe ich sie in Threads ausgelagert. Ich hoffe jetzt einfach mal, 263 Zeilen sind noch im Post erlaubt. :)

Wenn ich den Quelltext noch kommentieren soll, schreib das. Ich habe nur gerade relativ wenig Zeit dazu.

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:
unit AudioLibraryExt;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, bass, MP3FileUtils,
  TntSysUtils, TntClasses, TypesExt;

type
  TAudioLibraryThread = class;
  TAudioLibrary = class;

  TAudioLibraryThreadType = (atRequired, atUpdate);

  TAudioInfoThreadData = record
    FileName: String;
    Priority: Integer;
    ThreadType: TAudioLibraryThreadType;
  end;
  PAudioInfoThreadData = ^TAudioInfoThreadData;      

  TAudioInfoChange = procedure(Sender: TObject; Info: PAudioInfo) of object;

  TAudioLibrary = class
  private
    fList: TList;
    fThread: TAudioLibraryThread;
    fThreads: TList;
    fOnInfoChange: TAudioInfoChange;

    function GetInfos(const FileName: String): TAudioInfo;
    function GetMP3Infos(const FileName: String): TAudioInfo;
    function GetGeneralInfos(const FileName: String): TAudioInfo;

    procedure UpdateFile(const FileName: String);
  public
    constructor Create;
    destructor Destroy; override;
    
    procedure Add(const FileName: String; ThreadType: TAudioLibraryThreadType); overload;

    procedure Add(const FileName: String; ThreadType: TAudioLibraryThreadType;
      Priority: Integer); overload;
    function Get(const FileName: String): PAudioInfo;

    property OnInfoChange: TAudioInfoChange read fOnInfoChange write fOnInfoChange;
  end;

  TAudioLibraryThread = class(TThread)
  protected
    procedure Execute; override;
  end;

var
  AudioLibrary: TAudioLibrary;

const
  apUpdate = -2;
  apDirectory = -1;
  apDefault = 0;
  apVisible = 1;
  apRequired = 2;

implementation

constructor TAudioLibrary.Create;
begin
  inherited Create;
  fList := TList.Create;
  fThreads := TList.Create;
  fThread := TAudioLibraryThread.Create(False);
  fOnInfoChange := nil;
end;

destructor TAudioLibrary.Destroy;
begin
  fList.Free;
  fThreads.Free;
  fList := nil;
  fThreads := nil;
  inherited Destroy;
end;

procedure TAudioLibrary.Add(const FileName: String; ThreadType: TAudioLibraryThreadType);
begin
  Add(FileName, ThreadType, 0);
end;

procedure TAudioLibrary.Add(const FileName: String; ThreadType: TAudioLibraryThreadType;
  Priority: Integer);
var Data: PAudioInfoThreadData; D2: TAudioInfoThreadData; i, Pos: Integer;
begin
  if not WideFileExists(FileName) then Exit;

  Data := New(PAudioInfoThreadData);
  Data.FileName := FileName;
  Data.Priority := Priority;

  Pos := 0;
  i := 0;

  while i < fThreads.Count-1 do
  begin
    D2 := TAudioInfoThreadData(fThreads[i]^);

    if D2.FileName = FileName then
    begin
      if D2.Priority = Priority then
        Exit
      else
        fThreads.Delete(i);
    end;

    if D2.Priority >= Priority then Pos := i+1;

    inc(i);
  end;

  if fThreads.Count >= Pos then
    fThreads.Insert(Pos, Data)
  else
    fThreads.Add(Data);
end;

function TAudioLibrary.Get(const FileName: String): PAudioInfo;
var i: Integer;
begin
  for i := 0 to fList.Count-1 do
    if TAudioInfo(fList[i]^).FileName = FileName then
    begin
      Result := fList[i];
      Exit;
    end;   

  Result := New(PAudioInfo);
  Result^ := GetInfos(FileName);
  fList.Insert(0, Result);    

  if Assigned(fOnInfoChange) then fOnInfoChange(Self, Result);
end;

function TAudioLibrary.GetInfos(const FileName: String): TAudioInfo;
var Ext: String;
begin
  Ext := AnsiLowerCase(ExtractFileExt(FileName));
  if Ext = '.mp3' then
    try
      Result := GetMP3Infos(FileName);
    except
      on EFOpenError do
      begin
        Result := GetGeneralInfos(FileName);   
        Result.IsValid := True;
      end
      else
      begin
        Result := GetGeneralInfos(FileName);
        Result.IsValid := True;
        raise;
      end;
    end
  else
    Result := GetGeneralInfos(FileName);
  Result.IsValid := True;
end;

function TAudioLibrary.GetMP3Infos(const FileName: String): TAudioInfo;
var MPEGInfo: TMPEGInfo; ID3Tag: TID3v2Tag; Stream: TTntFileStream;
begin
  MPEGInfo := TMPEGInfo.Create;
  ID3Tag := TID3v2Tag.Create;
  try
    Stream := TTntFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
    try
      ID3Tag.ReadFromStream(Stream);
      if not ID3Tag.Exists then
        Stream.Seek(0, soBeginning)
      else
        Stream.Seek(ID3Tag.Size, soFromBeginning);
      MPEGInfo.LoadFromStream(Stream);
    finally
      Stream.Free;
    end;

    if ID3Tag.Title <> '' then
      Result.Title := ID3Tag.Title
    else
      Result.Title := Copy(ExtractFileName(FileName), 0,
        System.Length(ExtractFileName(FileName))-System.Length(ExtractFileExt(FileName)));

    Result.Artist := ID3Tag.Artist;
    Result.Album := ID3Tag.Album;
    Result.Length := MPEGInfo.dauer;
    Result.FileName := FileName;
  finally
    MPEGInfo.Free;
    ID3Tag.Free;
  end;
end;

function TAudioLibrary.GetGeneralInfos(const FileName: String): TAudioInfo;
var Stream: DWord; BassFileName: String;
begin
  BassFileName := FileName;
  Stream := BASS_StreamCreateFile(False, PChar(BassFileName), 0, 0, 0);
  try
    BASS_ChannelPlay(Stream, True);
    Result.Length := Round(BASS_ChannelBytes2Seconds(Stream, BASS_ChannelGetLength(Stream)));
  finally

    BASS_StreamFree(Stream);
  end;

  Result.Title := Copy(ExtractFileName(FileName), 0,
    System.Length(ExtractFileName(FileName))-System.Length(ExtractFileExt(FileName)));
  Result.Artist := '';
  Result.Album := '';
  Result.FileName := FileName;
end;

procedure TAudioLibrary.UpdateFile(const FileName: String);
var i: Integer; Info: PAudioInfo;
begin
  for i := 0 to fList.Count-1 do
    if TAudioInfo(fList[i]^).FileName = FileName then
    begin
      if Assigned(fOnInfoChange) then fOnInfoChange(Self, fList[i]);
      Exit;
    end;

  Info := New(PAudioInfo);
  Info^ := GetInfos(FileName);
  fList.Insert(0, Info);

  if Assigned(fOnInfoChange) then fOnInfoChange(Self, Info);
end;

procedure TAudioLibraryThread.Execute;
var Data: PAudioInfoThreadData;
begin
  while True do
  try
    if AudioLibrary.fThreads.Count = 0 then
    begin
      Priority := tpIdle;
      Sleep(100);
      Application.ProcessMessages;     
      Continue;
    end;

    Priority := tpNormal;
    Data := AudioLibrary.fThreads[0];
    AudioLibrary.UpdateFile(Data.FileName);
    AudioLibrary.fThreads.Delete(0);
  except
    on E: EAccessViolation do;
    on E: Exception do Application.MessageBox(PChar(E.Message), 'Fehler', 16);
  end;
end;

initialization
finalization
  AudioLibrary.Free;
  AudioLibrary := nil;
end.
(Aus: AudioPlayer, Version 0.2.3. © user profile iconYogu, 2008.)
Sauger Chris Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 228

Win XP, Linux SuSE 9.2
Delphi 4,Delphi 7 Ent.
BeitragVerfasst: Do 23.10.08 19:07 
@Yogu

danke das hilft mir schon mal sehr =)
wen du morgen bissle zeit hast kannst ja den Quelltext noch grob kommentieren ;)


thx schon mal für dein source


chris
DeddyH
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Do 23.10.08 19:18 
Du könntest aber auch mal im Verzeichnis {DELPHI}\Demos\Threads nachsehen, da gibt es ein Beispiel mit Sortieralgorithmen.
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Do 23.10.08 21:35 
user profile iconSauger Chris hat folgendes geschrieben Zum zitierten Posting springen:
@delfiphan

wen möglich würde ich gern per threads das laden von meiner listbox beschleunigen wen das nicht möglich ist
wenigstens das einfrieren des Main programmes wärend dem ladevorgang zu umgehen :)

Etwas in einen Thread auszulagern beschleunigt eigentlich nichts (ausser wenn du mehrere Threads gleichzeitig auf einer Multi-Core CPU nutzst).

Eine Datei kannst du relativ schnell mit LoadFromFile laden. Wenn dir die Geschwindigkeit nicht reicht, kannst du auf eine virtuelle Liste umsteigen oder auf eine Komponente, die thread-safe ist.

Um das Einfrieren zu verhindern kannst du z.B. je 10000 Zeilen in einem BeginUpdate/EndUpdate Block hinzufügen und danach jeweils Application.ProcessMessages aufrufen. Alternativ von einem Thread aus in einem Synchronize jeweils 10000 Zeilen aufs Mal hinzufügen. Alternativ zu Threads kämen evtl. Fibers in Frage (da keine Thread-Safety-Probleme), ist aber nicht sehr verbreitet und untypisch für OOP Code.

Persönlich würde ich eine virtuelle Liste bevorzugen. Dann kannst du die Datei in einem Thread in eine non-GUI Liste einlesen und danach diese sofort anzeigen lassen.