| Autor |
Beitrag |
Sauger Chris
      
Beiträge: 228
Win XP, Linux SuSE 9.2
Delphi 4,Delphi 7 Ent.
|
Verfasst: 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
|
Verfasst: Mi 22.10.08 17:18
|
|
delfiphan
      
Beiträge: 2684
Erhaltene Danke: 32
|
Verfasst: Mi 22.10.08 17:50
VCL ist nicht thread-safe. Du darfst den Inhalt einer Listbox in einem Thread nicht ändern.
|
|
jaenicke
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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
      
Beiträge: 2684
Erhaltene Danke: 32
|
Verfasst: Mi 22.10.08 20:30
jaenicke hat folgendes geschrieben : | | 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
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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
      
Beiträge: 2684
Erhaltene Danke: 32
|
Verfasst: 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
      
Beiträge: 2598
Erhaltene Danke: 156
Ubuntu 13.04, Win 7
C# (VS 2013)
|
Verfasst: 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 
      
Beiträge: 228
Win XP, Linux SuSE 9.2
Delphi 4,Delphi 7 Ent.
|
Verfasst: 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
|
Verfasst: 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
      
Beiträge: 2598
Erhaltene Danke: 156
Ubuntu 13.04, Win 7
C# (VS 2013)
|
Verfasst: Do 23.10.08 18:57
DeddyH hat folgendes geschrieben : | | 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.
Sauger Chris hat folgendes geschrieben : | | 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.
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. |
|
|
Sauger Chris 
      
Beiträge: 228
Win XP, Linux SuSE 9.2
Delphi 4,Delphi 7 Ent.
|
Verfasst: 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
|
Verfasst: 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
      
Beiträge: 2684
Erhaltene Danke: 32
|
Verfasst: Do 23.10.08 21:35
Sauger Chris hat folgendes geschrieben : | @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.
|
|