2013-07-30 41 views
8

Tôi có một lớp bên trong DLL của mình. Và DLL này cung cấp một "giao diện" để tạo các đối tượng của lớp này và gọi các phương thức của chúng.DLL và lớp trong ứng dụng đa luồng

Mã lớp (giản thể):

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; 

mã 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; 

Khi tôi đang cố gắng để sử dụng thư viện này từ ngày 1 chủ đề - tất cả mọi thứ là OK. Các vấn đề bắt đầu khi tôi tạo ra nhiều chủ đề gọi hàm AddToLog với các khoảng thời gian ngẫu nhiên (mỗi luồng có đối tượng riêng của lớp đó). Trong một thời gian, tôi bắt được Access Violation hoặc Invalid pointer operation. Tôi đã thực hiện một số nghiên cứu và chỉ ra rằng nếu biến Temp2WideString hãy nhập mọi thứ là OK. Một giải pháp khác là để di chuyển mutex vào mã thư viện (nó chỉ là một "nghiên cứu" 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; 

Giải pháp thứ hai là xấu đối với tôi bởi vì mỗi đối tượng có mutex riêng của nó (ý tưởng được rằng nếu hai đối tượng phải làm việc với một tập tin, họ có cùng một mutex để chờ đợi nhau, nếu hai đối tượng phải làm việc với các tập tin khác nhau, họ có mutexes khác nhau và làm việc song song).

Tôi đang cố gắng giải quyết vấn đề này trong 2 ngày nhưng tôi không thể hiểu điều gì sai. Làm thế nào chuỗi đúc có thể gây ra vấn đề như vậy?

+0

Dường như với tôi rằng bạn đã xóa quá nhiều mã. Mã mà bạn có ở đây là luồng an toàn ngay cả khi bạn loại bỏ các mutex, và ngay cả khi tất cả các chủ đề được chia sẻ cùng một ví dụ của logger. Bạn cần một SSCCE. –

+5

Bạn có đặt ['IsMultiThread'] (http://docwiki.embarcadero.com/Libraries/XE4/en/System.IsMultiThread): = True; trong DLL? –

+0

@TOndrej Ah, tôi cá là vậy. Với 'IsMultiThread' là' False', trình phân bổ heap sẽ không phải là luồng an toàn. Tôi đề nghị bạn thêm nó như một câu trả lời. –

Trả lời

14

Đặt dòng sau:

IsMultiThread := True; 

như dòng đầu tiên trong khối mã chính dự án DLL của bạn. Điều này sẽ hướng dẫn người quản lý bộ nhớ chuyển sang chế độ an toàn chỉ.

này sẽ giải thích sự khác biệt giữa hành vi AnsiStringWideStringAnsiString được phân bổ bởi người quản lý bộ nhớ Delphi, và WideString được cấp phát trên heap COM. Khi IsMultiThreadFalse, trình quản lý bộ nhớ Delphi không an toàn với luồng, nhưng đống COM luôn an toàn.

+0

+1 Lưu ý rằng WideString là chủ đề an toàn nhưng cũng chậm hơn nhiều so với AnsiString hoặc UnicodeString. Ngay cả khi tốc độ phân bổ hệ thống BSTR đã tăng lên rất nhiều kể từ Windows Vista, đối với XP hoặc 2K. –

+0

Điều này đã giúp tôi giải quyết vấn đề tôi đã phải vật lộn trong 3 ngày. Tôi đang sử dụng các đối tượng COM có thể gọi callbacks của tôi từ các chủ đề khác nhau.Tôi đã theo đuổi các lỗi lạ liên quan đến phân bổ mảng (de), giao diện giải phóng và tham chiếu sai số xung quanh mã do điều kiện chủng tộc bí ẩn ... Tôi thực sự đã làm không biết rằng trình quản lý bộ nhớ Delphi mặc định không phải là chủ đề an toàn trừ khi bạn kích hoạt nó. –