thread取得的值與全域變數的問題? |
答題得分者是:aftcast
|
lkkplayer
一般會員 發表:26 回覆:59 積分:17 註冊:2006-11-22 發送簡訊給我 |
請教各位大大,小弟有各疑惑我用一個Thread去接收我送命令給另外一支程式AP回傳的值
回傳的格式會是COUNT1234,1234是我要的數值我會把值(1234)給全域的變數RetrunCount 並把flRetrunData 設成true 給function ShowMisData使用 最後是顯示在utform這個form的label(1234) 我確定我有收到COUNT1234也解析正確 只是在function ShowMisData內卻完全不知道flRetrunData已經是true與RetrunCount=1234 請大家為小弟指點一下迷津...thx [code cpp] unit utMain; ...... TClientUi2MisThread = class(TThread) private CB: TCommBlock2; public glRetrunCount : String; flgHaveData : boolean; procedure HandleInput; protected procedure Execute; override; end; var frmMain : TfrmMain; ClientUi2MisThread: TClientUi2MisThread; Client2 : TIdTCPClient; RetrunCount : String; flRetrunData : boolean; procedure TClientUi2MisThread.Execute; var strMsg:string; begin while not Terminated do begin try if not Client2.Connected then begin Client2.Disconnect; Client2.Connect(1000); strMsg:='重新連線到 Ui2MisServer APP 成功。'; ShowMsg(strMsg);//StatusBar.Panels[4].Text := strMsg; //Terminate end else try Client2.ReadBuffer(CB, Sizeof(CB)); Synchronize(HandleInput); except on E:Exception do begin if Client2.Connected then Client2.Disconnect; //frmMain.tmAutoConnSvr.Enabled := True; end; end; except begin strMsg := '重新連線到 Ui2MisServer AP 失敗。'; ShowMsg(strMsg); sleep(2000); continue; end; end; end; end; procedure TClientUi2MisThread.HandleInput; var strMsg : string; begin if CB.Command = 'MESSAGE' then ShowMsg(CB.MyName ' sends message : ' CB.Data) else // // Read DATA // if CB.Command = 'DATA' then begin //ShowMsg(CB.MyName ' sends ver-data : ' CB.Data); ShowMsg(CB.MyName ' sends data : ' CB.Data); // if Copy(CB.Data, 1, 5) = 'COUNT' then begin RetrunCount:=trim( Copy(CB.Data, 6, 10) ); ShowMsg('Get Data Record: ' RetrunCount); //frmMain.HideSplashMsg; flRetrunData := true; end; end; end; function TfrmMain.ShowMisData : integer; var tmpTime :integer; begin tmpTime:= 0; Result := 0; SendMisCmd('GET COUNT','MIS',QALL_Count,'',''); while (1=1) do begin if (flRetrunData = true) then begin Result:=strtoint(RetrunCount); break; end; sleep(1000); tmpTime := tmpTime 1; if tmpTime >= 30 then break; end; end; procedure TfrmMain.SendMisCmd(const strCommand,strUseOdbc,strMisSql,strLocalSql,strMyName : string); var CB1 : TCommBlock2; strWhere :string; begin CB1.Command := strCommand; CB1.UseOdbc := strUseOdbc; CB1.MisSql := strMisSql; CB1.LocalSql := strLocalSql; CB1.Data := ''; CB1.MyName := Client2.Socket.Binding.IP; //Client2.LocalName; CB1.RecvName := ''; Client2.WriteBuffer(CB1, SizeOf(TCommBlock2(CB1)), True); end; unit utform; procedure TfrmInform.FormCreate(Sender: TObject); begin label.Caption := format('MIS筆數: %d',[frmMain.ShowMisData]); end; [/code] 編輯記錄
lkkplayer 重新編輯於 2008-11-14 01:09:07, 註解 無‧
|
syntax
尊榮會員 發表:26 回覆:1139 積分:1258 註冊:2002-04-23 發送簡訊給我 |
看不懂,你要問什麼,重點在哪,也看不出來你的步驟(你要做什麼?)
只是在function ShowMisData內卻完全不知道flRetrunData已經是true與RetrunCount=1234 ????When and where ? ===================引 用 lkkplayer 文 章=================== 請教各位大大,小弟有各疑惑我用一個Thread去接收我送命令給另外一支程式AP回傳的值 回傳的格式會是COUNT1234,1234是我要的數值我會把值(1234)給全域的變數RetrunCount 並把flRetrunData 設成true 給function ShowMisData使用 最後是顯示在utform這個form的label(1234) 我確定我有收到COUNT1234也解析正確 只是在function ShowMisData內卻完全不知道flRetrunData已經是true與RetrunCount=1234 請大家為小弟指點一下迷津...thx [code cpp] unit utMain; ...... TClientUi2MisThread = class(TThread) private CB: TCommBlock2; public glRetrunCount : String; flgHaveData : boolean; procedure HandleInput; protected procedure Execute; override; end; var frmMain : TfrmMain; ClientUi2MisThread: TClientUi2MisThread; Client2 : TIdTCPClient; RetrunCount : String; flRetrunData : boolean; procedure TClientUi2MisThread.Execute; var strMsg:string; begin while not Terminated do begin try if not Client2.Connected then begin Client2.Disconnect; Client2.Connect(1000); strMsg:='重新連線到 Ui2MisServer APP 成功。'; ShowMsg(strMsg);//StatusBar.Panels[4].Text := strMsg; //Terminate end else try Client2.ReadBuffer(CB, Sizeof(CB)); Synchronize(HandleInput); except on E:Exception do begin if Client2.Connected then Client2.Disconnect; //frmMain.tmAutoConnSvr.Enabled := True; end; end; except begin strMsg := '重新連線到 Ui2MisServer AP 失敗。'; ShowMsg(strMsg); sleep(2000); continue; end; end; end; end; procedure TClientUi2MisThread.HandleInput; var strMsg : string; begin if CB.Command = 'MESSAGE' then ShowMsg(CB.MyName ' sends message : ' CB.Data) else // // Read DATA // if CB.Command = 'DATA' then begin //ShowMsg(CB.MyName ' sends ver-data : ' CB.Data); ShowMsg(CB.MyName ' sends data : ' CB.Data); // if Copy(CB.Data, 1, 5) = 'COUNT' then begin RetrunCount:=trim( Copy(CB.Data, 6, 10) ); ShowMsg('Get Data Record: ' RetrunCount); //frmMain.HideSplashMsg; flRetrunData := true; end; end; end; function TfrmMain.ShowMisData : integer; var tmpTime :integer; begin tmpTime:= 0; Result := 0; SendMisCmd('GET COUNT','MIS',QALL_Count,'',''); while (1=1) do begin if (flRetrunData = true) then begin Result:=strtoint(RetrunCount); break; end; sleep(1000); tmpTime := tmpTime 1; if tmpTime >= 30 then break; end; end; procedure TfrmMain.SendMisCmd(const strCommand,strUseOdbc,strMisSql,strLocalSql,strMyName : string); var CB1 : TCommBlock2; strWhere :string; begin CB1.Command := strCommand; CB1.UseOdbc := strUseOdbc; CB1.MisSql := strMisSql; CB1.LocalSql := strLocalSql; CB1.Data := ''; CB1.MyName := Client2.Socket.Binding.IP; //Client2.LocalName; CB1.RecvName := ''; Client2.WriteBuffer(CB1, SizeOf(TCommBlock2(CB1)), True); end; unit utform; procedure TfrmInform.FormCreate(Sender: TObject); begin label.Caption := format('MIS筆數: %d',[frmMain.ShowMisData]); end; [/code] |
2007
中階會員 發表:54 回覆:90 積分:98 註冊:2008-08-12 發送簡訊給我 |
TfrmInform.FormCreate <--- TfrmInform 的建立(TfrmInform.FormCreate)是如何觸發的??? ===================引 用 lkkplayer 文 章=================== 請教各位大大,小弟有各疑惑我用一個Thread去接收我送命令給另外一支程式AP回傳的值 回傳的格式會是COUNT1234,1234是我要的數值我會把值(1234)給全域的變數RetrunCount 並把flRetrunData 設成true 給function ShowMisData使用 最後是顯示在utform這個form的label(1234) 我確定我有收到COUNT1234也解析正確 只是在function ShowMisData內卻完全不知道flRetrunData已經是true與RetrunCount=1234 請大家為小弟指點一下迷津...thx [code cpp] unit utMain; ...... TClientUi2MisThread = class(TThread) private CB: TCommBlock2; public glRetrunCount : String; flgHaveData : boolean; procedure HandleInput; protected procedure Execute; override; end; var frmMain : TfrmMain; ClientUi2MisThread: TClientUi2MisThread; Client2 : TIdTCPClient; RetrunCount : String; flRetrunData : boolean; procedure TClientUi2MisThread.Execute; var strMsg:string; begin while not Terminated do begin try if not Client2.Connected then begin Client2.Disconnect; Client2.Connect(1000); strMsg:='重新連線到 Ui2MisServer APP 成功。'; ShowMsg(strMsg);//StatusBar.Panels[4].Text := strMsg; //Terminate end else try Client2.ReadBuffer(CB, Sizeof(CB)); Synchronize(HandleInput); except on E:Exception do begin if Client2.Connected then Client2.Disconnect; //frmMain.tmAutoConnSvr.Enabled := True; end; end; except begin strMsg := '重新連線到 Ui2MisServer AP 失敗。'; ShowMsg(strMsg); sleep(2000); continue; end; end; end; end; procedure TClientUi2MisThread.HandleInput; var strMsg : string; begin if CB.Command = 'MESSAGE' then ShowMsg(CB.MyName ' sends message : ' CB.Data) else // // Read DATA // if CB.Command = 'DATA' then begin //ShowMsg(CB.MyName ' sends ver-data : ' CB.Data); ShowMsg(CB.MyName ' sends data : ' CB.Data); // if Copy(CB.Data, 1, 5) = 'COUNT' then begin RetrunCount:=trim( Copy(CB.Data, 6, 10) ); ShowMsg('Get Data Record: ' RetrunCount); //frmMain.HideSplashMsg; flRetrunData := true; end; end; end; function TfrmMain.ShowMisData : integer; var tmpTime :integer; begin tmpTime:= 0; Result := 0; SendMisCmd('GET COUNT','MIS',QALL_Count,'',''); while (1=1) do begin if (flRetrunData = true) then begin Result:=strtoint(RetrunCount); break; end; sleep(1000); tmpTime := tmpTime 1; if tmpTime >= 30 then break; end; end; procedure TfrmMain.SendMisCmd(const strCommand,strUseOdbc,strMisSql,strLocalSql,strMyName : string); var CB1 : TCommBlock2; strWhere :string; begin CB1.Command := strCommand; CB1.UseOdbc := strUseOdbc; CB1.MisSql := strMisSql; CB1.LocalSql := strLocalSql; CB1.Data := ''; CB1.MyName := Client2.Socket.Binding.IP; //Client2.LocalName; CB1.RecvName := ''; Client2.WriteBuffer(CB1, SizeOf(TCommBlock2(CB1)), True); end; unit utform; procedure TfrmInform.FormCreate(Sender: TObject); begin label.Caption := format('MIS筆數: %d',[frmMain.ShowMisData]); end; [/code] |
lkkplayer
一般會員 發表:26 回覆:59 積分:17 註冊:2006-11-22 發送簡訊給我 |
syntax大大:
不好意思,小弟寫的有點亂,我解釋一下我程式的順序 1.frmMain是我主程式的視窗(大略的程式如下),有個Button1會去開另一個視窗frmInform 2.當按下Button1開啟frmInform時,會觸發TfrmInform.FormCreate 3.FormCreate事件中會呼叫主程式(function)frmMain.ShowMisData 4.(function)frmMain.ShowMisData中SendMisCmd('GET COUNT','MIS',QALL_Count,'','');會送命令給另外一支程式AP 5.進入while迴圈,等待AP回送需要的資訊。 6.procedure TClientUi2MisThread.HandleInput;中會去接收資訊並解析RetrunCount,並把flRetrunData設成true 現在問題點來了,小弟原本以為在while迴圈,等待的時間中,TClientUi2MisThread.HandleInput應該就會接收到資訊 解析出RetrunCount,並把flRetrunData設成true 讓frmMain.ShowMisData這個function可以回傳值給視窗frmInform顯示出來 但是經小弟測試後,感覺進入while迴圈後好像把TClientUi2MisThread的主控權拿走了 等到我的計數器到了跳出while迴圈後,TClientUi2MisThread才又開始運作, 這個時候TClientUi2MisThread.HandleInput;才真的有接收到資訊解析出RetrunCount,並把flRetrunData設成true 這樣反而造成我這行程式label.Caption := format('MIS筆數: %d',[frmMain.ShowMisData]);筆數永遠都是0 請大大為小弟指點一下迷津...thx ===================引 用 syntax 文 章=================== 看不懂,你要問什麼,重點在哪,也看不出來你的步驟(你要做什麼?) 只是在function ShowMisData內卻完全不知道flRetrunData已經是true與RetrunCount=1234 ????When and where ? ===================引 用 lkkplayer 文 章=================== 請教各位大大,小弟有各疑惑我用一個Thread去接收我送命令給另外一支程式AP回傳的值 回傳的格式會是COUNT1234,1234是我要的數值我會把值(1234)給全域的變數RetrunCount 並把flRetrunData 設成true 給function ShowMisData使用 最後是顯示在utform這個form的label(1234) 我確定我有收到COUNT1234也解析正確 只是在function ShowMisData內卻完全不知道flRetrunData已經是true與RetrunCount=1234 請大家為小弟指點一下迷津...thx [code cpp] unit utMain; ...... TClientUi2MisThread = class(TThread) private CB: TCommBlock2; public glRetrunCount : String; flgHaveData : boolean; procedure HandleInput; protected procedure Execute; override; end; var frmMain : TfrmMain; ClientUi2MisThread: TClientUi2MisThread; Client2 : TIdTCPClient; RetrunCount : String; flRetrunData : boolean; procedure TClientUi2MisThread.Execute; var strMsg:string; begin while not Terminated do begin try if not Client2.Connected then begin Client2.Disconnect; Client2.Connect(1000); strMsg:='重新連線到 Ui2MisServer APP 成功。'; ShowMsg(strMsg);//StatusBar.Panels[4].Text := strMsg; //Terminate end else try Client2.ReadBuffer(CB, Sizeof(CB)); Synchronize(HandleInput); except on E:Exception do begin if Client2.Connected then Client2.Disconnect; //frmMain.tmAutoConnSvr.Enabled := True; end; end; except begin strMsg := '重新連線到 Ui2MisServer AP 失敗。'; ShowMsg(strMsg); sleep(2000); continue; end; end; end; end; procedure TClientUi2MisThread.HandleInput; var strMsg : string; begin if CB.Command = 'MESSAGE' then ShowMsg(CB.MyName ' sends message : ' CB.Data) else // // Read DATA // if CB.Command = 'DATA' then begin //ShowMsg(CB.MyName ' sends ver-data : ' CB.Data); ShowMsg(CB.MyName ' sends data : ' CB.Data); // if Copy(CB.Data, 1, 5) = 'COUNT' then begin RetrunCount:=trim( Copy(CB.Data, 6, 10) ); ShowMsg('Get Data Record: ' RetrunCount); //frmMain.HideSplashMsg; flRetrunData := true; end; end; end; function TfrmMain.ShowMisData : integer; var tmpTime :integer; begin tmpTime:= 0; Result := 0; SendMisCmd('GET COUNT','MIS',QALL_Count,'',''); while (1=1) do begin if (flRetrunData = true) then begin Result:=strtoint(RetrunCount); break; end; sleep(1000); tmpTime := tmpTime 1; if tmpTime >= 30 then break; end; end; procedure TfrmMain.SendMisCmd(const strCommand,strUseOdbc,strMisSql,strLocalSql,strMyName : string); var CB1 : TCommBlock2; strWhere :string; begin CB1.Command := strCommand; CB1.UseOdbc := strUseOdbc; CB1.MisSql := strMisSql; CB1.LocalSql := strLocalSql; CB1.Data := ''; CB1.MyName := Client2.Socket.Binding.IP; //Client2.LocalName; CB1.RecvName := ''; Client2.WriteBuffer(CB1, SizeOf(TCommBlock2(CB1)), True); end; ------------------------------------------------------------------------------------------------------ unit utform; procedure TfrmInform.FormCreate(Sender: TObject); begin label.Caption := format('MIS筆數: %d',[frmMain.ShowMisData]); end; [/code] |
2007
中階會員 發表:54 回覆:90 積分:98 註冊:2008-08-12 發送簡訊給我 |
lkkplayer 大大:
知道你的問題在那兒了,我以前也遇到,但還是沒找到答案!! 呵~~~ 會不會覺得這樣肥答粉xxxxx。 我以前也是用 while 迴圈,等待另一個程序的結束或一個值,但好像只要 while 一執行,就就就會一直執行至結束, 如:你程式中,若無 if tmpTime >= 30 then break;,真得是變成無窮迴圈, 也不知如何(用什麼語法),把執行權先釋放給別的正在等待執行權的程序, 執行緒真的不是粉好寫,也許功力不足吧,加上底子不深,沒去好好研究執行緒,半路出家真素累。 我想就讓別人幫我們找到答案吧!!!!! ===================引 用 lkkplayer 文 章=================== syntax大大: 不好意思,小弟寫的有點亂,我解釋一下我程式的順序 1.frmMain是我主程式的視窗(大略的程式如下),有個Button1會去開另一個視窗frmInform 2.當按下Button1開啟frmInform時,會觸發TfrmInform.FormCreate 3.FormCreate事件中會呼叫主程式(function)frmMain.ShowMisData 4.(function)frmMain.ShowMisData中SendMisCmd('GET COUNT','MIS',QALL_Count,'','');會送命令給另外一支程式AP 5.進入while迴圈,等待AP回送需要的資訊。 6.procedure TClientUi2MisThread.HandleInput;中會去接收資訊並解析RetrunCount,並把flRetrunData設成true 現在問題點來了,小弟原本以為在while迴圈,等待的時間中,TClientUi2MisThread.HandleInput應該就會接收到資訊 解析出RetrunCount,並把flRetrunData設成true 讓frmMain.ShowMisData這個function可以回傳值給視窗frmInform顯示出來 但是經小弟測試後,感覺進入while迴圈後好像把TClientUi2MisThread的主控權拿走了 等到我的計數器到了跳出while迴圈後,TClientUi2MisThread才又開始運作, 這個時候TClientUi2MisThread.HandleInput;才真的有接收到資訊解析出RetrunCount,並把flRetrunData設成true 這樣反而造成我這行程式label.Caption := format('MIS筆數: %d',[frmMain.ShowMisData]);筆數永遠都是0 請大大為小弟指點一下迷津...thx |
jow
尊榮會員 發表:66 回覆:751 積分:1253 註冊:2002-03-13 發送簡訊給我 |
|
RootKit
資深會員 發表:16 回覆:358 積分:419 註冊:2008-01-02 發送簡訊給我 |
原因:
當你 Synchronize(HandleInput); 時 Delphi 是調用 MainThread (Thread Window 由MainThread 創建)來處理 HandleInput。 此時又因 ShowMisData 掉入無窮迴圈,導致 Synchronize(等待MainThread 回傳訊息) 無法切換至 MainThread。 解決: 可以嘗試將 SLEEP 改為 ProcessMessage,但也可能發生事件卡死的問題。 建議重新思考,誰主動通知誰被動。 將 ShowMisData 拆成只傳送命令 ->當Thread 處理完成後可 PostMessage 給主視窗依據帶入參數作判斷處理。 一來避免視窗呆掉,二來提高效率。 |
RootKit
資深會員 發表:16 回覆:358 積分:419 註冊:2008-01-02 發送簡訊給我 |
補充:
使用 Synchronize 要非常小心,裡面的事件越簡單越好。以免干擾 MainThread 運作。 Synchronize 裡會 SendMessage (會等待訊息,Thread 此時是等待狀態)給由 MainThread 所建立的視窗Delphi 巧妙利用這點切換至MainThread 。 但因此時已進入 While 迴圈中,導致由 MainThread 所建立的視窗不會即時接收到訊息(MainThread 沒空閒處理Windows訊息)。 這就所以當 ShowMisData TimeOut 結束時,才會收到的原因。 一般可能會用 CreateEvent 及WaitForMultipleObjects 來處理這類的問題。 |
lkkplayer
一般會員 發表:26 回覆:59 積分:17 註冊:2006-11-22 發送簡訊給我 |
jow 大大:
我試用一下您的方法 我將ShowMisData這個function改寫如下: 結果還是接收不到值,另外我再加Sleep程式就直接當掉了 是我誤會您的意思了嗎? [code cpp] function TfrmMain.ShowMisData : integer; var tmpTime :integer; BytesRead : integer; CB : TCommBlock2; begin tmpTime:= 0; Result := 0; SendMisCmd('GET COUNT','MIS2',QALL_T0NBRK07_Count,'',''); //Sleep(1000); BytesRead := Client2.Socket.Recv(CB, Sizeof(CB)); if BytesRead > 0 then begin Result:=strtoint(RetrunCount); ShowMsg('等待ok'); end; end; [/code] ===================引 用 jow 文 章=================== 矇著眼猜猜看 改用 BytesRead := Client2.Socket.Recv(CB, Sizeof(CB)); if BytesRead > 0 then begin end; 看看可否Work? |
lkkplayer
一般會員 發表:26 回覆:59 積分:17 註冊:2006-11-22 發送簡訊給我 |
RootKit大大:
我想試試看看CreateEvent 及WaitForMultipleObjects 的方法,只是我不知道從哪裡著手?? ===================引 用 RootKit 文 章=================== 補充: 使用 Synchronize 要非常小心,裡面的事件越簡單越好。以免干擾 MainThread 運作。 Synchronize 裡會 SendMessage (會等待訊息,Thread 此時是等待狀態)給由 MainThread 所建立的視窗Delphi 巧妙利用這點切換至MainThread 。 但因此時已進入 While 迴圈中,導致由 MainThread 所建立的視窗不會即時接收到訊息(MainThread 沒空閒處理Windows訊息)。 這就所以當 ShowMisData TimeOut 結束時,才會收到的原因。 一般可能會用 CreateEvent 及WaitForMultipleObjects 來處理這類的問題。 |
lkkplayer
一般會員 發表:26 回覆:59 積分:17 註冊:2006-11-22 發送簡訊給我 |
RootKit大大:
如果ShowMisData只傳命令->當Thread 處理完成後PostMessage 給主視窗依據帶入參數作判斷處理。 那我另外一個視窗frmInform可以先停下來,等待筆數回傳回來,那該怎麼處理呢? 先前以為是可以用call function(ShowMisData)的方法那它停在fuction那邊等值傳回來 但現在看起來好像不可能,有比較好的方法嗎? 另外想請教說我之前有用過SendMessage作為兩支程式的溝通,PostMessage 是相同的用法嗎?有啥差別? 現在是在同一支程式做溝通,這樣會不會影響到Thread的控制權壓~~ [code cpp] procedure TfrmInform.FormCreate(Sender: TObject); begin label.Caption := format('MIS筆數: %d',[frmMain.ShowMisData]); <-停下來等待 //下方還有一些程式碼需要用到筆數? end; [/code] ===================引 用 RootKit 文 章=================== 原因: 當你 Synchronize(HandleInput); 時 Delphi 是調用 MainThread (Thread Window 由MainThread 創建)來處理 HandleInput。 此時又因 ShowMisData 掉入無窮迴圈,導致 Synchronize(等待MainThread 回傳訊息) 無法切換至 MainThread。 解決: 可以嘗試將 SLEEP 改為 ProcessMessage,但也可能發生事件卡死的問題。 建議重新思考,誰主動通知誰被動。 將 ShowMisData 拆成只傳送命令 ->當Thread 處理完成後可 PostMessage 給主視窗依據帶入參數作判斷處理。 一來避免視窗呆掉,二來提高效率。 |
aftcast
站務副站長 發表:81 回覆:1485 積分:1763 註冊:2002-11-21 發送簡訊給我 |
你的程式架構很不順,晚點再深入的討論…
先用你原來的方法來使它功能正常,請把你的程式碼改成如下 while (1=1) do begin if (CheckSynchronize(1) = false) then continue; //加入這一行 if (flRetrunData = true) then 我正打算要寫一篇關於thread的所有議題,等ok了再po上來給大家參考
------
蕭沖 --All ideas are worthless unless implemented-- C++ Builder Delphi Taiwan G+ 社群 http://bit.ly/cbtaiwan |
aftcast
站務副站長 發表:81 回覆:1485 積分:1763 註冊:2002-11-21 發送簡訊給我 |
RootKit 說的觀念很正確,但唯Synchronize 裡會 SendMessage 這裡是不對的。
事實上Synchronize 是用PostMessage然後post一個WM_NULL給TApplication的WndProc,WndProc收這個個msg後,就會去執行CheckSynchronize。 此外,當Synchronize執行完PostMessage後會再執行一個WaitForSingleObject的api,故使得thread暫時呈現suspend的狀態,直到…MainThread把你交待的工作完成時,WaitForSingleObject反回,而Synchronize方法也返回,thread也因此又再繼續下去… PostMessage WaitForSingleObject 的二個動作是很像SendMessage,但還是有所不同的! 補充: 事實上篇我請提問者修改加入一行CheckSynchronize,其實改加入Application.ProcessMessages,也應該是可行的,試看看。 ===================引 用 RootKit 文 章=================== Synchronize 裡會 SendMessage (會等待訊息,Thread 此時是等待狀態)給由 MainThread 所建立的視窗Delphi 巧妙利用這點切換至MainThread 。 但因此時已進入 While 迴圈中,導致由 MainThread 所建立的視窗不會即時接收到訊息(MainThread 沒空閒處理Windows訊息)。 這就所以當 ShowMisData TimeOut 結束時,才會收到的原因。
------
蕭沖 --All ideas are worthless unless implemented-- C++ Builder Delphi Taiwan G+ 社群 http://bit.ly/cbtaiwan |
lkkplayer
一般會員 發表:26 回覆:59 積分:17 註冊:2006-11-22 發送簡訊給我 |
aftcast大大:
我試用了您的方法可以了耶!!@@ 這是為什麼?用CheckSynchronize(1)判斷是否繼續?不太瞭解這個函式,另外那個參數(1)有什麼差別嗎? 真的是太神奇了~~~ 我對Thread的瞭解連皮毛都算不上,請aftcast大大指導一下我的程式架構,我是看不太出來我的程式架構哪不順?? 我終於可以先去吃飯了@@~~~ PS:CheckSynchronize是同步處理的意思嗎? ===================引 用 aftcast 文 章=================== 你的程式架構很不順,晚點再深入的討論… 先用你原來的方法來使它功能正常,請把你的程式碼改成如下 while (1=1) do begin if (CheckSynchronize(1) = false) then continue; //加入這一行 if (flRetrunData = true) then 我正打算要寫一篇關於thread的所有議題,等ok了再po上來給大家參考 |
lkkplayer
一般會員 發表:26 回覆:59 積分:17 註冊:2006-11-22 發送簡訊給我 |
aftcast大大:
我剛剛繼續試用了一下,加Application.ProcessMessages 也是可以耶~~雖然都可以達到目的但是兩者有什麼差別嗎? ===================引 用 lkkplayer 文 章=================== aftcast大大: 我試用了您的方法可以了耶!!@@ 這是為什麼?用CheckSynchronize(1)判斷是否繼續?不太瞭解這個函式,另外那個參數(1)有什麼差別嗎? 真的是太神奇了~~~ 我對Thread的瞭解連皮毛都算不上,請aftcast大大指導一下我的程式架構,我是看不太出來我的程式架構哪不順?? 我終於可以先去吃飯了@@~~~ PS:CheckSynchronize是同步處理的意思嗎? ===================引 用 aftcast 文 章=================== 你的程式架構很不順,晚點再深入的討論… 先用你原來的方法來使它功能正常,請把你的程式碼改成如下 while (1=1) do begin if (CheckSynchronize(1) = false) then continue; //加入這一行 if (flRetrunData = true) then 我正打算要寫一篇關於thread的所有議題,等ok了再po上來給大家參考 |
aftcast
站務副站長 發表:81 回覆:1485 積分:1763 註冊:2002-11-21 發送簡訊給我 |
CheckSynchronize這個函數算是一個較隱密少人知的函數。一般來說是不可能直接被我們叫用。它只有當Application收到WM_NULL時,或是當Application Idle的時候才會自動的被叫用。
我請你加了這一行其實是很暴力的直接叫用。其實你可以把那行改成Application.ProcessMessages; 這樣也可以間接的叫用CheckSynchronize,而這樣的使用方式應該也比較安全。用暴力法事實上是為了讓更多人了解細節,必竟單看ProcessMessages這行會誤會其真正的用意… 參數(1)中的1是指timeout的時間,不寫也是可以。設定1只是想讓你的while不會跑太快,有點像是sleep的意味。而CheckSynchronize並非只是"檢查",它更是"執行"你給的工作。不要被Check這個字給騙了! 此外,若要知道一點詳情,請看上篇我回rootkit的文。 你的架構問題,我本想好好的說明一下,但想一想我也不是很清楚你整個程式的目的,故可能無法很正確完整的重構。我只針對幾點說明。 1/ 你的procedure TClientUi2MisThread.HandleInput; 裡面看不出有什麼 none thread safe的function。 除了ShowMsg這個函數比較可疑,因為你也沒列出它是這麼樣子的。如果說ShowMsg也沒用到什麼vcl元件,或者你乾脆把它換成MessageBox,那麼你就不需要使用 Synchronize(HandleInput); 直接改成 HandleInput(); //沒用vcl就無需synchronize 要知道用Synchronize是很不得已的事,因為它讓效能變很差。 2/ 事實上我也不知道為何你會需要使用thread來處理收資料。也許你有你的理由…但若是單純的情形下,照你使用ShowMisData 的狀態,其實也許不需要thread。為什麼? 因為當你按下button後,產生一個form,from的create又去叫ShowMisData,而ShowMisData本身又進入一個loop裡… 這時候,注意一個現象: 對使用者來說按下button後,可能就進入了一個等待的狀態,直到新form完全的收到資料並展現答案。那麼試想,我們可否把thread裡的工作直接放到create事件裡?? 這樣就不需要thread了。反正對使用者來說,感覺是一樣的。我用概念寫一下流程 FormCreate裡 --> SendMisCmd --> Client2.ReadBuffer --> RetrunCount:=trim( Copy(CB.Data, 6, 10) ) --> label.Caption := format('MIS筆數: %d',[frmMain.ShowMisData]); 3/ 如果真的有需要使用thead,那麼使用CreateEvent WaitForSingle(Multiple)Object 的方式才是最佳的。 以上的架構僅提供參考,也許不完全適用你現在的情形。最重要的還是功能要正常!! PS這幾天我會找時間整理一下關於thread的所有議題內容,可能會把心得與教學放到我的blog並貼文至ktop。到時候再請多指教了!
------
蕭沖 --All ideas are worthless unless implemented-- C++ Builder Delphi Taiwan G+ 社群 http://bit.ly/cbtaiwan |
RootKit
資深會員 發表:16 回覆:358 積分:419 註冊:2008-01-02 發送簡訊給我 |
不懂不要亂講。
我講的是 D5 你講的是 D7。 ===================引 用 aftcast 文 章=================== RootKit 說的觀念很正確,但唯Synchronize 裡會 SendMessage 這裡是不對的。 事實上Synchronize 是用PostMessage然後post一個WM_NULL給TApplication的WndProc,WndProc收這個個msg後,就會去執行CheckSynchronize。 此外,當Synchronize執行完PostMessage後會再執行一個WaitForSingleObject的api,故使得thread暫時呈現suspend的狀態,直到…MainThread把你交待的工作完成時,WaitForSingleObject反回,而Synchronize方法也返回,thread也因此又再繼續下去… PostMessage WaitForSingleObject 的二個動作是很像SendMessage,但還是有所不同的! 補充: 事實上篇我請提問者修改加入一行CheckSynchronize,其實改加入Application.ProcessMessages,也應該是可行的,試看看。 ===================引 用 RootKit 文 章=================== Synchronize 裡會 SendMessage (會等待訊息,Thread 此時是等待狀態)給由 MainThread 所建立的視窗Delphi 巧妙利用這點切換至MainThread 。 但因此時已進入 While 迴圈中,導致由 MainThread 所建立的視窗不會即時接收到訊息(MainThread 沒空閒處理Windows訊息)。 這就所以當 ShowMisData TimeOut 結束時,才會收到的原因。
編輯記錄
RootKit 重新編輯於 2008-11-15 16:03:02, 註解 無‧
|
aftcast
站務副站長 發表:81 回覆:1485 積分:1763 註冊:2002-11-21 發送簡訊給我 |
|
RootKit
資深會員 發表:16 回覆:358 積分:419 註冊:2008-01-02 發送簡訊給我 |
|
lkkplayer
一般會員 發表:26 回覆:59 積分:17 註冊:2006-11-22 發送簡訊給我 |
RootKit大大:
您指的是這一段程式的改寫嗎? [code cpp] procedure TClientUi2MisThread.Execute; .......... Client2.ReadBuffer(CB, Sizeof(CB); Synchronize(HandleInput); ............ [/code] ===================引 用 RootKit 文 章=================== 針對讀取或寫入共用部分直接用 EnterCriticalSection 段處理不要透過 Synchronize 繞一大圈。 如: EnterCriticalSection(RWLock); try ReadBuffer..... or WriteBuffer finally LeaveCriticalSection(RWLock); end; 處理顯示部分 這樣就比較單純化。繼續使用 SLEEP 大計。 剛才跟別人干架心情不好,對 aftcast 語氣不好的地方見諒 |
lkkplayer
一般會員 發表:26 回覆:59 積分:17 註冊:2006-11-22 發送簡訊給我 |
aftcast大大:
1.none thread safe的function,我不太清楚您指的是?ShowMsg只是單純把訊息寫到畫面的一個Memo,讓我可以看到程式進行到哪裡。 至於你的建議,我倒是沒有想過,因為前人就已經是用Thread接收資料 FormCreate--> SendMisCmd --> Client2.ReadBuffer --> RetrunCount:=trim( Copy(CB.Data, 6, 10) ) --> label.Caption := format('MIS筆數: %d',[frmMain.ShowMisData]); 可以用while把Client2.ReadBuffer 包起來接收資料嗎? 2.CreateEvent WaitForSingle(Multiple)Object 又聽到這個啦!!Rootkit大大也有這樣子建議,只是小弟不才 不知道如何直接使用在我目前的程式,有什麼建議的文章或範例可以參考嗎? PS:aftcast大大的關於thread的所有議題內容大作.......期待中.. ===================引 用 aftcast 文 章=================== CheckSynchronize這個函數算是一個較隱密少人知的函數。一般來說是不可能直接被我們叫用。它只有當Application收到WM_NULL時,或是當Application Idle的時候才會自動的被叫用。 我請你加了這一行其實是很暴力的直接叫用。其實你可以把那行改成Application.ProcessMessages; 這樣也可以間接的叫用CheckSynchronize,而這樣的使用方式應該也比較安全。用暴力法事實上是為了讓更多人了解細節,必竟單看ProcessMessages這行會誤會其真正的用意… 參數(1)中的1是指timeout的時間,不寫也是可以。設定1只是想讓你的while不會跑太快,有點像是sleep的意味。而CheckSynchronize並非只是"檢查",它更是"執行"你給的工作。不要被Check這個字給騙了! 此外,若要知道一點詳情,請看上篇我回rootkit的文。 你的架構問題,我本想好好的說明一下,但想一想我也不是很清楚你整個程式的目的,故可能無法很正確完整的重構。我只針對幾點說明。 1/ 你的procedure TClientUi2MisThread.HandleInput; 裡面看不出有什麼 none thread safe的function。 除了ShowMsg這個函數比較可疑,因為你也沒列出它是這麼樣子的。如果說ShowMsg也沒用到什麼vcl元件,或者你乾脆把它換成MessageBox,那麼你就不需要使用 Synchronize(HandleInput); 直接改成 HandleInput(); //沒用vcl就無需synchronize 要知道用Synchronize是很不得已的事,因為它讓效能變很差。 2/ 事實上我也不知道為何你會需要使用thread來處理收資料。也許你有你的理由…但若是單純的情形下,照你使用ShowMisData 的狀態,其實也許不需要thread。為什麼? 因為當你按下button後,產生一個form,from的create又去叫ShowMisData,而ShowMisData本身又進入一個loop裡… 這時候,注意一個現象: 對使用者來說按下button後,可能就進入了一個等待的狀態,直到新form完全的收到資料並展現答案。那麼試想,我們可否把thread裡的工作直接放到create事件裡?? 這樣就不需要thread了。反正對使用者來說,感覺是一樣的。我用概念寫一下流程 FormCreate裡 --> SendMisCmd --> Client2.ReadBuffer --> RetrunCount:=trim( Copy(CB.Data, 6, 10) ) --> label.Caption := format('MIS筆數: %d',[frmMain.ShowMisData]); 3/ 如果真的有需要使用thead,那麼使用CreateEvent WaitForSingle(Multiple)Object 的方式才是最佳的。 以上的架構僅提供參考,也許不完全適用你現在的情形。最重要的還是功能要正常!! PS這幾天我會找時間整理一下關於thread的所有議題內容,可能會把心得與教學放到我的blog並貼文至ktop。到時候再請多指教了! |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |