2012-01-10 24 views
10

Điều cơ bản tôi muốn là bắt đầu AsyncCall và tiếp tục tải mã của tôi. Tôi có phần giao diện tiêu thụ rất nhiều thời gian (600 + ms) và tôi muốn tải mã này trong chuỗi độc lập.AsyncCall với Delphi 2007

Tôi đã cố gắng sử dụng AsyncCall để làm một cái gì đó như thế này:

procedure Load; 
begin 
... 
end; 

initialization 
    AsyncCall(@Load, []); // or LocalAsyncCall(@Load) 

Tuy nhiên, thủ tục Load này thực sự bắt đầu trong chủ đề chính và không có trong các chủ đề đã tạo mới. Làm cách nào để buộc quy trình Load được tải trong bất kỳ chuỗi nào khác ngoài MainThread?

Tôi có thể tạo TThreadExecute điều này nhưng tôi muốn bắt buộc AsyncCall hoặc LocalAsyncCall hoặc bất kỳ thứ gì từ thư viện AsyncCall để hoạt động.

Cảm ơn sự giúp đỡ của bạn.

+0

Không. Không hoạt động.Ngay cả khi tôi đặt nó ra khỏi khởi tạo nhưng tải thủ tục trên một số nút giả. –

Trả lời

5

Sự cố là mã của bạn không giữ lại giao diện IAsyncCall được trả về bởi hàm AsyncCall.

AsyncCall(@Load, []); 
//AsyncCall returns an IAsyncCall interface, 
//but this code does not take a reference to it 

Do đó, giao diện được trả lại có số tham chiếu được giảm xuống 0 ngay khi phần khởi tạo hoàn tất. Điều này do đó giải phóng các đối tượng mà thực hiện các giao diện mà thực hiện điều này:

destructor TAsyncCall.Destroy; 
begin 
    if FCall <> nil then 
    begin 
    try 
--> FCall.Sync; // throw raised exceptions here 
    finally 
     FCall.Free; 
    end; 
    end; 
    inherited Destroy; 
end; 

Điểm mấu chốt là cuộc gọi đến Sync mà lực lượng các cuộc gọi không đồng bộ được thực hiện để hoàn thành. Tất cả điều này xảy ra trong chuỗi chính giải thích hành vi mà bạn báo cáo.


Giải pháp là bạn chỉ cần giữ giao diện IAsyncCall còn sống bằng cách lưu trữ nó trong một biến.

var 
    a: IAsyncCall; 

initialization 
    a := AsyncCall(@Load, []); 

Trong mã thực bạn cần phải đảm bảo rằng Load đã hoàn thành trước khi chạy bất kỳ mã đó là phụ thuộc vào Load. Khi chương trình của bạn đạt đến một điểm mà nó yêu cầu Load để được gọi thì phải gọi Sync trên giao diện IAsyncCall.

Vì vậy, bạn có thể viết nó như thế này.

unit MyUnit; 

interface 

procedure EnsureLoaded; 

implementation 

uses 
    AsyncCalls; 

.... 

procedure Load; 
begin 
    .... 
end; 

var 
    LoadAsyncCall: IAsyncCall; 

procedure EnsureLoaded; 
begin 
    LoadAsyncCall := nil;//this will effect a call to Sync 
end; 

initialization 
    LoadAsyncCall := AsyncCall(@Load, []); 

end. 

Gọi EnsureLoaded từ các đơn vị khác yêu cầu Load để chạy. Hoặc, cách khác, hãy gọi EnsureLoaded từ bất kỳ phương thức nào được xuất bởi MyUnit phụ thuộc vào Load khi chạy. Tùy chọn thứ hai có đóng gói tốt hơn nhiều.

+0

Tôi đã thử điều này và bạn đã đúng. Nhưng cố gắng để làm cho điểm phanh trên dòng điều kiện đó và bạn sẽ thấy rằng nhấp vào cả hai button1 hoặc button2 bạn sẽ nhận được cùng một ID thread - nó nhập vào MyProc từ cùng một chủ đề. Và khi tôi làm điều đó trong mã chính của tôi (không phải ứng dụng thử nghiệm) tôi thấy rằng thủ tục tải được thực hiện trong chủ đề chính, không phải trong thread someother. Ngoài ra tôi không thể đặt bất kỳ giấc ngủ vào phần khởi tạo gây ra rằng một phần nên làm việc tối đa nhanh chóng. Nhưng ngay cả khi tôi đặt nó là như nhau .. :( –

+0

@Ivan Rõ ràng tôi không gợi ý rằng 'Sleep' là câu trả lời. 'Sleep' không bao giờ là câu trả lời cho bất kỳ câu hỏi nào! Tôi chỉ cố gắng giải thích những gì đang diễn ra Dù sao, tôi chắc chắn rằng kobik đã chỉ cho bạn giải pháp. –

+0

Tất nhiên, cảm ơn vì sự giúp đỡ và nỗ lực của tôi. Thật không may khi tôi nhận được kết quả và mã số như vậy luôn luôn được thực hiện trong Tôi sợ rằng phiên bản Delphi là xấu và AnsycCall lib hoạt động tốt với năm 2009 và cao hơn.Trong ngày mai, tôi sẽ thử phiên bản Delphi mới nhất và sẽ loại bỏ khả năng này. –

8

Các bạn đã thử một cái gì đó như thế này ?:

procedure Load; 
begin 
    if GetCurrentThreadId <> MainThreadID then 
    Beep; 
end; 

var a: IAsyncCall; 

initialization 
    a := AsyncCall(@Load, []); 
    a.ForceDifferentThread; 

ForceDifferentThread() cho AsyncCalls rằng chức năng được phân công phải không được thực hiện trong thread hiện hành.

+5

+1 rất tốt thực sự. –

+0

Tôi đã thử điều đó và nó không giúp ích gì. Sản xuất cùng một kết quả - hoạt động trong mã chính thay vì trong chuỗi riêng biệt. –

+0

@Ivan Bạn có thể cho thấy một bản sao tối thiểu của điều đó. Khi tôi đã cố gắng ForceDifferentThread trong mã của tôi nó đã thực sự chạy phương pháp asynch trong một chủ đề khác nhau. –

Các vấn đề liên quan