2012-01-10 109 views
10

我基本上想要的是開始AsyncCall並繼續我的代碼加載。我有消耗大量時間(600 +毫秒)的接口部分,我想在獨立線程中加載此代碼。AsyncCall與德爾福2007

我試圖用AsyncCall做出這樣的事情:

procedure Load; 
begin 
... 
end; 

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

然而,這Load過程實際上開始在主線程,而不是在新創建的線程。我如何強制Load程序被加載到除MainThread以外的任何線程中?

我可以創建TThreadExecute這一點,但我想強制AsyncCallLocalAsyncCall或任何從AsyncCall庫進行工作。

感謝您的幫助。

+0

沒有。不工作。即使我把它從初始化中刪除,但在某個虛擬按鈕上加載過程。 – 2012-01-10 19:33:40

回答

5

問題是您的代碼沒有保留由AsyncCall函數返回的IAsyncCall接口。

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

因此,一旦初始化部分完成,返回的接口將其引用計數遞減爲零。因此這釋放了實現該執行此界面上的對象:

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

關鍵線是這迫使被執行以完成異步調用Sync呼叫。所有這些都發生在解釋你報告行爲的主線程中。


的解決方案是,你只需要保持IAsyncCall接口活活將其存儲在一個變量。

var 
    a: IAsyncCall; 

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

在您需要確保Load已運行是Load依賴任何代碼前完成真正的代碼。當您的程序達到要求撥打Load的點時,必須在IAsyncCall接口上撥打Sync

所以你可能會寫這樣的東西。

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. 

從其他單位所需Load有運行調用EnsureLoaded。或者,可以從MyUnit導出的任何方法調用EnsureLoaded,這些方法依賴Load運行。後面的選項有更好的封裝。

+0

我試過這個,你說得對。但是嘗試在該條件行上製作剎車點,並且您會看到單擊button1或button2時,您將收到相同的線程ID - 它將從同一線程進入MyProc。 而當我在我的主代碼(而不是測試應用程序)中這樣做時,我看到Load過程在主線程中執行,而不是在其他線程中執行。 另外我不能把任何睡眠放入初始化部分,導致那部分應該工作得最快。但是即使我把它放在一起.. :( – 2012-01-10 22:52:46

+0

@Ivan很明顯,我並不是說「睡眠」就是答案,「睡眠」從來不是任何問題的答案!我只是想解釋發生了什麼事情並給你一些線索,無論如何,我非常肯定kobik已經指出你的解決方案 – 2012-01-10 22:55:49

+0

當然,感謝您的幫助和努力,不幸的是我做了什麼我收到了相同的結果,並且代碼總是在MainThread,恐怕Delphi版本不好,而且AnsycCall lib在2009及更高版本中工作良好。明天在辦公室,我會嘗試使用最新的Delphi版本,並且將消除這種可能性。 如果不是,那麼我將創建myown線程 – 2012-01-10 23:00:23

8

你有沒有嘗試過這樣的事情?:

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

var a: IAsyncCall; 

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

ForceDifferentThread()告訴AsyncCalls所分配的功能必須 不能在當前線程執行。

+5

+1非常好。 – 2012-01-10 22:39:19

+0

我試過了,並沒有幫助。產生相同的結果 - 在主代碼中工作,而不是在單獨的線程中工作。 – 2012-01-10 22:39:45

+0

@伊萬你能展示一個最小的再現嗎?當我在代碼中嘗試ForceDifferentThread時,確實在另一個線程中運行異步方法。 – 2012-01-10 22:48:33