Active Form 中不能用 Thread 嗎? |
尚未結案
|
silence
一般會員 發表:9 回覆:17 積分:10 註冊:2003-06-04 發送簡訊給我 |
我在 Active Form 上 (main TActiveForm , 或是產生出來的 TForm 上)
都不能執行 Thread
沒有 hang 住, 只是沒有反應
直接引用 Delphi\Demo 中的 Thread Sorting Demo 也是一樣
也使用過
myThread := TmyThread.Create(....);
myThread.Resume;
和
with TmyThread.Create(....) do
Resume;
的方式都不行 Active Form 中要可以使用 Thread , 是跟
initialization
TActiveFormFactory.Create(
ComServer,
TActiveFormControl,
TActiveFormX,
Class_ActiveFormX,
1,
'',
OLEMISC_SIMPLEFRAME or OLEMISC_ACTSLIKELABEL,
tmApartment);
中的 Thread Model 有關嗎? 還是 [red]myThread 也要像 subform 一樣宣告在 Public ??[red]
|
silence
一般會員 發表:9 回覆:17 積分:10 註冊:2003-06-04 發送簡訊給我 |
再描述清楚一點
我是用前人的方法
將 [設計好的專案], 從 Active Form 中引入, 做成 ocx 發布到 client
(不是 AP 層的 Multi-Thread) 但是, 發布之後的 ocx, 原本專案中好好的 Thread 都無法執行
也測試過直接將 Thread 寫在 TActiveForm 裡面, 都依樣無法執行 我嘗試過把 Thread 的 Synchronize(Run) 去掉, 改成只有 Run 而已
結果是可以執行,
但是就要用 Application.ProcessMessgae 來避免獨占
那這樣一來, 就和我單純使用 procedure 來做是一樣的結果 所以, 主題該是 : OCX 裡面的 Multi-Thread 怎麼做 有先進遇過這個問題嗎? 相關的搜尋都沒有符合的..
|
李國維
高階會員 發表:42 回覆:287 積分:235 註冊:2003-02-07 發送簡訊給我 |
|
powerhowardchen
初階會員 發表:15 回覆:28 積分:28 註冊:2004-04-19 發送簡訊給我 |
雖然我早就知道 TThread.Synchronize 必須要有 TApplication 才能運作, 不過我之前都是採迂迴的做法(像是自己寫 Signal 與 Mutex 來處理). 試了一下, 這次試出答案了. PS. ( 小弟我發了小瘋, 寫了以下的一段廢話, 如果你要直接看答案, 可以直接跳過問題原因 ) 首先我要先說明問題原因: 1. 執行序同步程式 TThread.Synchronize() [Classes:9556] , 它是將欲同步的程式 AMethod 排入同步串列 SyncList, 發出 SyncEvent, 然後等待 SyncProc.Signal, 當代表程式被執行的 SyncProc.Signal 被處發時, 則任務完畢. TThread.Synchronize() [Classes:9556] 的運作方式如下:
a. 建立 SyncRec, 將 Thread 本身 與 要執行同步的程式 SyncRec.FMethod (TThreadMethod) 紀錄進去
b. 使用 EnterCriticalSection(ThreadLock) 與 LeaveCriticalSection(ThreadLock) 以阻擋其他 Thread 使用 SyncList (讓其他要加入 Synchronize 的 Thread 先等一下).
c. 將 SyncRec.FSyncRec 依附著 SyncProc (TSyncProc) 加入到 SyncList, SyncList 是用於記錄多筆將要同步的 SyncRec.FMethod
d. 觸發 SyncEvent , 要求執行同步
e. 等待 SyncProc.Singal 被觸發, 然後離開 2. SyncProc.Singal 的接收程式則在 WaitForSyncEvent() [Classes:9267], 並且是由 CheckSynchronize() [Classes:9313] 所取用. CheckSynchronize() 的運作方式如下:
a. 檢查是否有 SyncEvent 發生
b. 使用 EnterCriticalSection(ThreadLock) 與 LeaveCriticalSection(ThreadLock)
以阻擋其他 Thread 使用 SyncList (讓其他要加入 Synchronize 的 Thread 先等一下).
c. 從 SyncList 取得將要執行同步的 SyncRec.FMethod , 然後執行 SyncRec.FMethod
d. 觸發 SyncProc.Singal , 回覆執行完畢的訊號
e. 重複 c 與 d 步驟, 直到 SyncList 被清空, 然後離開 3. CheckSynchronize 主要在三處被執行, ㄧ是 Application.WndProc(), 另ㄧ是 Application.Idle(), 還有一個是在 TThread.WaitFor(); 最後一個跟本次問題無關. 4. 但是問題來了, 前兩個 Application.WndProc() 與 Application.Idle() 執行位置所造成的問題是, 執行 ActiveFormX 的應用程式, 不見得是 Delphi/BCB 的 TApplication 的應用程式, 而且, 就算是 Delphi/BCB 的 TApplication 的應用程式, 該應用程式內的 CheckSynchronize 的 SyncEvent 與 SyncList 也將跟 ActiveFormX 內的不一樣, 所以造成了應用程式不會接收 SyncEvent 也不會處理 SyncRec.FMethod 的情況.
由此可知, 結論是, 不只是 ActiveFormX 會有此一問題, 舉凡若是應用程式沒有 CheckSynchronize 可執行, 或是非為 TApplication 的程式都會出問題 (如 Netscape 的 Plugin, 應用程式為非 Delphi 或是沒用 ShareMem 的 DLL, ActiveScript 內被建立的 ActiveObject 等). ==================================================
Howard Chen.
Delphi, Java 我的神.....
.NET 垃圾筒在哪裡?...
|
powerhowardchen
初階會員 發表:15 回覆:28 積分:28 註冊:2004-04-19 發送簡訊給我 |
解決方法(建立執行 CheckSynchronize 的替代方案): 1. 將 "procedure WndProc(var Message: TMessage); override;" 加入自己的 ActiveForm 中
2. WndProc(var Message: TMessage); 內加入 CheckSynchronize;
3. 建立 "TFlushMshTimerThread = class(TThread)" 讓該 Thread 定時觸發 CheckSynchronize
解決方法衍生的懷疑:
1. 在 WndProc(var Message: TMessage); 內加入 CheckSynchronize; 時, 為什麼不去過濾 Message.Msg ?
A: 在原本執行 CheckSynchronize 的 TApplication.WndProc 中,
CheckSynchronize 是在 Message.Msg=WM_NULL 才執行的;
而我之所以取消過濾, 是由於把 ActiveForm 在 IE 測試時, 發現 IE 根本不會傳入 WM_NULL,
甚至連ㄧ般的訊息都會被 IE 濾掉而不常送進來, 可以確定的是, 當有滑鼠或是按鍵事件在該區域被觸發時,
才會傳入訊息.
2. 為什麼增加 TFlushMshTimerThread ?
A: 原本 CheckSynchronize 的另ㄧ個執行程式是在 Application.Idle() 中,
而 Idle() 其實是執行 CheckSynchronize 的最大功臣, 它可以讓 CheckSynchronize 幾乎可以定時被執行,
但是現在沒有處理 Idle() 的 Application.HandleMessage; ,
所以建立 TFlushMshTimerThread 讓它定時去觸發 CheckSynchronize, 觸發的方式當然是用 Message 最好啦,
Execute 就寫成傳送 WM_NULL 給 ActiveForm 的 WndProc 即可. 下面這是 Sample 片段: ////////////////////////////////////////////////////////////////////////////////
type
TTestThreadActiveForm = class(TActiveForm, ITestActiveFormX)
...
procedure ActiveFormCreate(Sender: TObject);
private
...
protected
procedure WndProc(var Message: TMessage); override;
public
...
end;
procedure TTestThreadActiveForm.WndProc(var Message: TMessage);
begin
CheckSynchronize;
inherited;
end; procedure TTestThreadActiveForm.ActiveFormCreate(Sender: TObject);
begin
TFlushMshTimerThread.Create(Handle);
end; ////////////////////////////////////////////////////////////////////////////////
type
TFlushMshTimerThread = class(TThread)
private
FMsgRecvHandle: THandle;
protected
procedure Execute; override;
public
constructor Create(AMsgRecvHandle: THandle);
end; constructor TFlushMshTimerThread.Create(AMsgRecvHandle: THandle);
begin
FMsgRecvHandle := AMsgRecvHandle;
inherited Create(False);
end; procedure TFlushMshTimerThread.Execute;
begin
while not Terminated do
begin
SendMessage(FMsgRecvHandle, WM_NULL, 0, 0);
Sleep(1000); // 間隔時間自己定
end;
end;
//////////////////////////////////////////////////////////////////////////////// ==================================================
Howard Chen.
Delphi, Java 我的神.....
.NET 垃圾筒在哪裡?...
|
powerhowardchen
初階會員 發表:15 回覆:28 積分:28 註冊:2004-04-19 發送簡訊給我 |
PS. 在測試程式中, 又發現了一樣的Delphi Bug, 就是, 只要是在 ActiveForm 同ㄧ個 Unit 內,
撰寫另外一個非視覺化物件(該物件的程式碼在TActiveForm之後), 並讓該物件與 ActiveForm 交互對照使用,
將會造成無法啟動該 ActiveForm 的錯誤,
錯誤訊息說是非法的存取了一個第0位址的資料, 我猜是 Delphi DLL 在記憶體被配置時,
因為無法正確取得該非視覺化物件的物件建構子所在的記憶體位置所造成的. 這是小弟土法煉鋼的, 還請各位大大指教.
==================================================
|
Ktop_Robot
站務副站長 發表:0 回覆:3511 積分:0 註冊:2007-04-17 發送簡訊給我 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |