Ho una classe nella DLL. E questa DLL fornisce una "interfaccia" per creare oggetti di questa classe e chiamare i loro metodi.DLL e classe nell'applicazione con multithreading
Codice classe (semplificato):
TLogger = class
private
//
public
function AddToLog(sBuf: PWideChar): Word;
constructor Create(Name: PWideChar);
destructor Destroy; override;
end;
constructor Create(Name: PWideChar);
begin
//
end;
destructor TLogger.Destroy;
begin
//
end;
function TLogger.AddToLog(sBuf: PWideChar): Word;
var
Temp1 : WideString;
Temp2 : AnsiString;
begin
Result := NO_ERRORS;
WaitForSingleObject(FMutex, INFINITE);
Temp1 := 'a';
Temp2 := Temp1;
//
ReleaseMutex(FMutex);
end;
codice DLL
function CreateLogger(LogFileName: PWideChar; PLogger: PCardinal): Word; stdcall;
begin
try
PLogger^ := Cardinal(TLogger.Create(LogFileName));
Result := NO_ERRORS;
except
Result := ERR_CREATE_OBJECT;
end;
end;
function DestroyLogger(PLogger: Cardinal): Word; stdcall;
begin
try
TLogger(PLogger).Free;
Result := NO_ERRORS;
except
Result := ERR_OBJECT_NOT_FOUND;
end;
end;
function AddToLog(PLogger: Cardinal; BufStr: PWideChar): Word; stdcall;
begin
try
Result := TLogger(PLogger).AddToLog(BufStr);
except
Result := ERR_OBJECT_NOT_FOUND;
end;
end;
Quando sto cercando di usare questa libreria dal 1 filo - tutto è OK. I problemi iniziano quando creo molti thread che chiamano la funzione AddToLog
con periodi casuali (ogni thread ha il proprio oggetto della classe). In un dato momento, prendo lo Access Violation
o lo Invalid pointer operation
. Ho fatto delle ricerche e ho sottolineato che se la variabile Temp2
ha il tipo WideString
, tutto è OK. Un'altra soluzione è quella di spostare mutex al codice della libreria (è solo un codice di "ricerca"):
function AddToLog(PLogger: Cardinal; BufStr: PWideChar): Word; stdcall;
begin
WaitForSingleObject(TLogger(PLogger).FMutex, INFINITE);
Result := TLogger(PLogger).AddToLog(BufStr);
ReleaseMutex(TLogger(PLogger).FMutex);
end;
La seconda soluzione è un male per me, perché ogni oggetto ha il proprio mutex (idea è che se due oggetti deve lavorare con un file, hanno lo stesso mutex che si aspettano a vicenda, se due oggetti devono lavorare con file diversi, hanno mutex diversi e funzionano in parallelo).
Sto provando a risolvere questo problema per 2 giorni ma non riesco a capire cosa vada storto. In che modo il cast di stringhe può causare questo problema?
Mi sembra di aver rimosso troppo codice. Il codice che hai qui è thread-safe anche se rimuovi il mutex e anche se tutti i thread condividono la stessa istanza del logger. Hai bisogno di un SSCCE. –
Imposta ['IsMultiThread'] (http://docwiki.embarcadero.com/Libraries/XE4/en/System.IsMultiThread): = True; nella DLL? –
@TOndrej Ah, scommetto che è tutto. Con 'IsMultiThread' come' False' l'allocatore dell'heap non sarà protetto da thread. Suggerisco di aggiungerla come risposta. –