最近遇到一個非常棘手的問題,復現頻率及其的低.
形同運行環境描述:
只在客戶端復現過(客戶端XP或者2003),我本地是win7
問題描述:
在程式的主界面放了一個定時器控制元件,定時器Timer事件的邏輯如下,
tmrWork.Enabled := False;
tmrWork.Interval := 30 * 1000; //不在運行時間,半分鐘檢測一次
TSecThread.Create(StrList);
TSecThread類如下
TSecThread = class(TThread)
private
strList:TStrings;
ConText : TConText;
public
procedure Execute; override;
procedure SetstrList(var strL:TStrings);
constructor Create(var strL:TStrings);
end;
constructor TSecThread.Create(var strL: TStrings);
begin
SetstrList(strL);
StataCon := TConText.Create(strList) ;
FreeOnTerminate := True;
inherited Create(False);
end;
在執行緒TSecThread.Execute中處理邏輯如下,try finally部分做了業務處理,然后在finally end部分做了定時器的處理
inherited;
try
ConText.NowState.SetNextState();
Sleep(100);
ConText.NowState.SetNextState();
Sleep(100);
ConText.NowState.SetNextState();
finally
if Assigned(ConText) then
freeandnil(ConText);
FmMain.tmrWork.Enabled := True;
end;
問題出現了,安裝上面的邏輯,只能有一個TSecThread執行緒在執行,可是有的時候會出現兩個TSecThread在執行,請問有人出現過這樣的問題沒有?怎么解決?
uj5u.com熱心網友回復:
沒明白你在說什么定時器可以放到執行緒中創建
uj5u.com熱心網友回復:
procedure TSecThread.Execute;
var
MsgRec: TMsg;
begin
inherited;
FCheckTimer := TTimer.Create(nil);
FCheckTimer.Interval := 30*1000;
FCheckTimer.OnTimer := procTimer;
FCheckTimer.Enabled := true;
while GetMessage(MsgRec, 0, 0, 0) do
begin
TranslateMessage(MsgRec);
DispatchMessage(MsgRec);
end;
FCheckTimer.Enabled := False;
FCheckTimer.free;
end;
procedure TSecThread.procTimer(Sender: TObject);
begin
FCheckTimer.Enabled := False;
try
//do something
finally
FCheckTimer.Enabled := true;
end;
end;
uj5u.com熱心網友回復:
我是要通過定時器來控制執行緒。uj5u.com熱心網友回復:
定時器不會很精確,你比如在TSecThread.Create(StrList);先做判斷,定時器是主執行緒運行。
uj5u.com熱心網友回復:
To:andrew57沒明白是什么意思.
uj5u.com熱心網友回復:
時間精準不重要,我的目錄是通過定時器控制執行緒的啟動,定時器觸發,把任務交給子執行緒處理,處理完,在將定時器激活,這樣保證我的執行緒無限的回圈運行,并且只有一個子執行緒在作業。但是現在的問題就是,有的時候他會出現兩個子執行緒同事在處理任務。
uj5u.com熱心網友回復:
定時器事件怎么寫的?另外,執行緒開始執行了,好像也沒關定時器的動作?只有最后開定時器的代碼
uj5u.com熱心網友回復:
沒必要用定時器,也沒必要反復創建和釋放執行緒,直接在 Execute 中寫一個回圈:repeat
// 這里是你的狀態邏輯陳述句
Sleep(30000); // 等待半分鐘重新開始
until Terminated;
這樣就能不斷回圈處理,直到你把 Terminated 設成 True。為了能在終止時盡快反應,可以把 Sleep 縮短,用回圈湊成半分鐘,中間不斷檢測 Terminated 條件。
uj5u.com熱心網友回復:
To:sz_haitao就是timer
To: jinghai1776
這個辦法比較好,不過看看還有其他的辦法沒有,改動有些大,這個是最后的選擇了。
uj5u.com熱心網友回復:
定時器事件怎么寫的?定時器事件的代碼沒貼,不知道里面怎么寫,有沒有先停止自己再啟動執行緒?
如果的確是每次執行完停止30秒再重新執行,的確可以在執行緒里sleep
uj5u.com熱心網友回復:
樓主不妨仔細思考下:你在執行緒里啟動主執行緒定時器,又在定時器事件創建新執行緒,這就很可能兩個執行緒同時存在,因為老執行緒釋放需要一定時間。而且這種現象是隨機的,因為這取決于作業系統如何分配 CPU 時間片。這種方案連想都不要想。uj5u.com熱心網友回復:
哦,原來已經貼了定時器的事件代碼了,是先停止自己再啟動執行緒
執行緒結束后再啟動定時器,定時器30秒后才又先停止自己再啟動執行緒
理論上,30秒的間隔是怎么都足夠老執行緒釋放的了
可能不釋放,只是暫停和重啟可能比較好
當然,本例直接在執行緒里暫停30秒更合理:簡單且可靠
uj5u.com熱心網友回復:
在timer中用 WaitForSingleObject(handle, 0);試試看uj5u.com熱心網友回復:
1.執行緒里面寫個死回圈,每次延遲半分鐘 不是一樣的效果么?2.可以定義一個全域變數 標識當前是否有前程在運行。
uj5u.com熱心網友回復:
沒看明白咋回事uj5u.com熱心網友回復:
不建議反復創建執行緒,如果TSecThread.create肯定是在你timer事件之外你還有執行過,我覺得TSecThread有兩個的原因不在timer,而是在timer之外TSecThread.create被執行過兩次。uj5u.com熱心網友回復:
試著將恢復定時器的代碼放到Thread的OnTerminate事件中uj5u.com熱心網友回復:
inherited;try
ConText.NowState.SetNextState();
Sleep(100);
ConText.NowState.SetNextState();
Sleep(100);
ConText.NowState.SetNextState();
finally
if Assigned(ConText) then
freeandnil(ConText);
FmMain.tmrWork.Enabled := True;
end;
---------------------------------------------------------
FmMain.tmrWork.Enabled := True;
這句有問題。TTimer是獨立于執行緒的物件。你這句應該用Synchronous執行。
uj5u.com熱心網友回復:
定時器本身就是一個執行緒吧.uj5u.com熱心網友回復:
同意樓上定時器本身就是執行緒uj5u.com熱心網友回復:
這個程式不是那么簡單就能把定時器放到執行緒中的,因為還很多邏輯需求。真不知道把分給誰,這個問題我自己似乎解決掉了,我模擬了一個信號,當執行緒創建時,信號+1,在執行執行緒的時候,如果信號>1則跳出,否則開始執行邏輯代碼。
我這樣更改,改動非常小。不知道以后還會不會出現這個問題,已經很長時間了,都沒有再次出現這個問題。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/137840.html
標籤:VCL組件開發及應用
