Mam klasę wewnątrz mojej biblioteki DLL. I ta biblioteka DLL zapewnia "interfejs" do tworzenia obiektów tej klasy i wywoływania ich metod.DLL i klasa w aplikacji wielowątkowej
kod klasy (uproszczony):
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;
kod 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;
Kiedy staram się korzystać z tej biblioteki z 1 gwintem - wszystko jest OK. Problemy zaczynają się, gdy tworzę wiele wątków, które wywołują funkcję AddToLog
z przypadkowymi okresami (każdy wątek ma własny obiekt klasy). W pewnym momencie łapię Access Violation
lub Invalid pointer operation
. Zrobiłem kilka badań i wskazałem, że jeśli zmienna Temp2
ma typ WideString
, wszystko jest w porządku. Innym rozwiązaniem jest przeniesienie mutex do kodu biblioteki (to tylko „badania” code):
function AddToLog(PLogger: Cardinal; BufStr: PWideChar): Word; stdcall;
begin
WaitForSingleObject(TLogger(PLogger).FMutex, INFINITE);
Result := TLogger(PLogger).AddToLog(BufStr);
ReleaseMutex(TLogger(PLogger).FMutex);
end;
Drugie rozwiązanie jest złe dla mnie, ponieważ każdy obiekt ma własną mutex (pomysł jest, że jeśli dwa obiekty muszą pracować z jednym plikiem mają ten sam muteks, aby czekać jeden drugiego, jeśli dwa obiekty muszą pracować z różnymi plikami, mają różne muteksy i działają równolegle).
Próbuję rozwiązać ten problem przez 2 dni, ale nie mogę zrozumieć, co jest nie tak. Jak odlewanie ciągów może powodować taki problem?
Wydaje mi się, że usunięto zbyt wiele kodu. Kod, który tu masz, jest bezpieczny dla wątków, nawet jeśli usuniesz muteks, a nawet jeśli wszystkie wątki współużytkują to samo wystąpienie rejestratora. Potrzebujesz SSCCE. –
Czy ustawić ['IsMultiThread'] (http://docwiki.embarcadero.com/Libraries/XE4/en/System.IsMultiThread): = True; w bibliotece DLL? –
@TOndrej Ah, założę się, że to wszystko. Z 'IsMultiThread' jako' False' alokator sterty nie będzie bezpieczny dla wątków. Proponuję dodać to jako odpowiedź. –