PDA

Visualizza la versione completa : [Delphi] Accedere a classe TThreadList da più thread


Andreach10
10-04-2012, 12:56
Ciao a tutti,
questo il mio problema.

ho creato, utilizzando graphics32, un piccolo "motore grafico" che utilizzo all'interno di un filtro directX. Tra i componenti di questo motore ci sono delle animazioni, che non sono altro che delle sequence di file anim000.tga ... anim100.tga.
il componente animazione utilizza un thread al suo interno per la lettura e l'eventuale elaborazione dei file.

Se io carico più animazioni dello stesso tipo in un progetto ho il problema che le varie animazioni, con i relativi threads, cercando di caricare nello stesso momento i file dal disco sollevano un'eccezione, essendo il "file utilizzato da un altro processo".

Domanda 1, come è possibile evitare ciò?

Proseguo...

per evitare di dover caricare più volte lo stesso file dal disco ho creato una classe che memorizza i file caricati in precedenza e se vengono richiesti li fornisce lei invcece di ricorrere all'HD...


PLoadedFile=^TLoadedFile;
TLoadedFile=record
Path : string;
FileStream : TMemoryStream;
Compressed : Boolean;
end;

PFileList = ^TFileList;
TFileList = class(TThreadList)
private
FB : TBitmap32;
procedure AddFile(APath: string);
public
constructor Create;
destructor Destroy; override;
procedure DeleteAll;
function LoadFile(APath: string): TStream;
end;


function TFileList.LoadFile(APath: string): TStream;
var LF : PLoadedFile;
i : integer;
found: boolean;
// List: TList;
begin
found := false;
// List := LockList;
try

if LockList.Count > 0 then
for i := 0 to LockList.Count - 1 do
begin
LF := LockList.Items[i];
if LF.Path = APath then
begin
Result := LF.FileStream;
Result.Position := 0;
found := true;
Break;
end;
end;

if not found then
begin
AddFile(APath);
LF := LockList.Items[LockList.Count-1];
Result := LF.FileStream;
Result.Position := 0;
end;
finally
UnlockList;
end;
end;






La cosa funziona solo per la prima animazione, le altre non caricano i file
e immagino sia perché quando l'animazione 1 carica i file blocca la lista
che le diventa inaccessibile agli altri.
Qual'è la soluzione migliore per risolvere il problema? usare un evento e un wait
sui thread di lettura o cosa?

spero di essere stato chiaro... sennò chiedete pure.

Grazie mille!


P.S: da quello che ho letto in giro, quando si legge da una TThread list bisognerebbe usare:

List := LockList;

Modificare List e poi


finally UnlockList;

ma non funzionava, infatti nel codice che ho postato utilizzo direttamente la LockList.
è un grosso problema?


Grazie,
Andrea.

alka
10-04-2012, 15:36
In linea generale, si deve solo tenere conto che TThreadList rappresenta una lista di oggetti che incorpora gli strumenti necessari per l'accesso sincronizzato da più thread alla lista stessa, e va utilizzata chiamando LockList (una sola volta) ottenendo come valore di ritorno la lista degli oggetti su cui lavorare (bloccando, cioè mettendo in attesa, gli altri thread) e invocando alla fine UnlockList quando l'uso della suddetta lista è terminato.

Se si fanno più chiamate a LockList, devono corrispondere altrettante chiamate a UnlockList, altrimenti la lista rimane bloccata.

La prassi di utilizzo si può schematizzare così:



var
List: TList;
begin
List := ThreadList.LockList;
try
// ...uso di List...
finally
ThreadList.UnlockList;
end;
end;


Se il meccanismo "non funziona", l'errore specifico è da ricercarsi altrove.

Ciao!

Andreach10
10-04-2012, 17:08
Grazie Marco....

ma quando il secondo thread prova ad accedere alla classe TFileList e la trova occupata
attende automaticamente che questa si liberi e poi prosegue o devo scrivere qualcosa io?

alka
10-04-2012, 18:06
Originariamente inviato da Andreach10
ma quando il secondo thread prova ad accedere alla classe TFileList e la trova occupata
attende automaticamente che questa si liberi e poi prosegue o devo scrivere qualcosa io?

Quando il secondo thread arriva alla chiamata di LockList, se la risorsa è occupata da un altro thread, si mette in attesa e prosegue l'esecuzione solo quando il thread libera la risorsa impegnata.

Andreach10
11-04-2012, 15:34
Ho trovato il problema.

In pratica:
creo contemporaneamente Animazione1 e Animazione2 e i relativi thread di lettura.

Animazione1, chiama LoadFile(): TStream, questo blocca la ThreadList, la quale viene rilasciata alla fine della funzione(*). a questo punto Animazione 1 inizia a copiare i dati dallo Stream nella propria cache.

Animazione2, appena la Thread List viene rilasciata dalla Animazione1 (*) inizia a copiare anche lei i dati dallo Stream alla sua cache; qui nasce il problema perchè Animazione1 non ha ancora terminato di farlo.


ho eliminato quindi l'UnlockList dalla fine della funzione LoadFile(), chiamandolo invece dalla classe Animazione dopo che i dati sono stati completamente prelevati dallo Stream.

Andrea.

Loading