2010-03-15 118 views
1

我是新來的...System.Threading.Timer不會觸發

我有一個問題,如果有人能幫助我。

它是關於定時器(System.Threading.Timer)。

我想打破不可避免的遞歸:我在datarow中有兩列,它們是相互依賴的(price_without_VAT和price_with_VAT)。設置其中的一個肯定會導致StackOverflowException。因此,這裏的想法:

bool flag = true; 
void Reset(object state) { flag = true; } 

現在,包裹方法改變其中一列的值:

{ 
    if(flag) 
    { 
     flag = false; 
     System.Threading.Timer tmr = new System.Threading.Timer(new System.Threading.TimerCallback(Reset), null, 10, System.Threading.Timeout.Infinite); 
     datarow.other_column = value; 
    } 
} 

datarow.other_column.value線將立即觸發上面的方法,但會有沒有遞歸,因爲標誌是錯誤的。 在10 ms標誌應該回到真,並且一切恢復正常。

現在,當我按照DEBUGGER中的代碼,一切工作正常,但是當我啓動應用程序NORMALLY復位功能根本不會觸發,標誌永遠被卡住爲假,一切都假分開。我玩due_time參數,但似乎沒有任何幫助。

任何想法?

回答

0

我不會這樣做。你將遇到計時問題。如果您試圖快速連續設置「標記」值,會發生什麼情況?這最多會導致奇怪的調試,最糟糕的是導致無效的數據被保存。

您可以將標記設置爲全局,將其設置爲一個屬性,然後在另一個屬性中進行檢查。設置標誌,更改該值,然後在完成後再設置標誌。或者,讓獲取者執行基礎計算,並且不允許明確設置其中一個值。

2

聽起來像你有各種討厭的比賽在這裏進行。你真的需要解決你的底層問題

2

看來你真正的問題是StackOverflow異常,由於非終止遞歸 - 你應該修復,然後不需要使用這樣的定時器。

+0

沒有,StackOverflow上是不可避免的。無論用戶選擇什麼,用戶都可以輸入含增值稅的價格或不含增值稅的價格我的工作是設置另一個,當然,打破遞歸。 – 2010-03-15 19:09:52

+0

包裝用戶在屬性中設置的列,當設置該屬性時,自動設置該屬性中的另一個屬性。聽起來不像這需要定時器。 – 2010-03-15 19:29:47

+1

@mijatovic - 我懷疑這是不可避免的 - 但是你打算用同步的計時器來防止它。 – Lee 2010-03-15 19:30:10

0

我不會在這裏使用計時器。什麼時候我有這樣的問題(這是不經常)我通常做的,就是沿着這些路線的東西:

bool _isSettingAOrB; 
private int _a; 
private void SetA(int value) 
{ 
    _a = value; 

    if (_isSettingAOrB) 
    { 
     return; 
    } 

    _isSettingAOrB = true; 

    try 
    { 
     SetB(_a - 10); 
    } 
    finally 
    { 
     _isSettingAOrB = false; 
    } 
} 

private int _b; 
private void SetB(int value) 
{ 
    _b = value; 

    if (_isSettingAOrB) 
    { 
     return; 
    } 

    _isSettingAOrB = true; 

    try 
    { 

     SetA(_b + 10); 
    } 
    finally 
    { 
     _isSettingAOrB = false; 
    } 
} 

如果你不喜歡重複的圖案(如上面的代碼),你可以包裹調用結構成代替一個單獨的方法:

bool _isSettingAOrB; 
private int _a; 
public void SetA(int value) 
{ 
    SetInterdependentValues(() => _a = value,() => SetB(_a - 10)); 
} 

private int _b; 
public void SetB(int value) 
{ 
    SetInterdependentValues(() => _b = value,() => SetA(_b + 10)); 
} 

private void SetInterdependentValues(Action primary, Action secondary) 
{ 
    primary(); 

    if (_isSettingAOrB) 
    { 
     return; 
    } 
    _isSettingAOrB = true; 
    try 
    { 
     secondary(); 
    } 
    finally 
    { 
     _isSettingAOrB = false; 
    } 
} 

代碼的簡單說明:

SetInterdependentValues(() => _a = value,() => SetB(_a - 10)); 

這是一個方法調用採用兩個參數。這兩個參數是() => _a = value() => SetB(_a - 10)。簡而言之,這些是lambda表達式,將轉換爲代表,其中每種方法的主體位於=>右側。因此,第一個參數是一個將value指定爲_a的方法,第二個參數將調用方法SetB,傳遞參數_a - 10

SetInterdependentValues將執行第一種方法,但只有在_isSettingAOrBfalse時才執行第二種方法。但是,在撥打電話之前,它會將_isSettingAOrB設置爲true。這將防止發生無限遞歸。最後一部分是在try-finally塊中完成的,以保證如果被調用的方法拋出異常,該標誌也會被重置。

+0

這聽起來不錯...但是,你是通過這種方式參數傳遞函數?但是,我仍然不知道這是否會有所幫助。我的更改發生在我訂閱的datarow的datacolumnchanged事件中,這意味着每當我更改一個值時,同一個事件將再次觸發,如果我不打破它,則永遠觸發。我可以在更改之前取消訂閱,並訂閱後,但這意味着其他值不會,也就是說,「更新」。 你認爲我可以用你的代碼完成我所需要的嗎?說實話,我需要一些時間來充分理解你的代碼。 – 2010-03-15 19:27:59

+0

@mijatovic:我無法保證DataColumnChanged事件的行爲如何(沒有使用它),但通常事件處理程序是同步調用的(它們在同一個線程上執行),所以我認爲它可以很好地工作。至於代碼如何工作,我會用一些解釋來更新答案。 – 2010-03-15 19:37:02

+0

我現在看到。好東西。雖然,爲了解決我的問題,我必須在更改任何值之前取消訂閱ColumnChanged事件,使其免於更改,然後再次訂閱。這就像使這兩個變化成爲原子。謝謝。很有幫助。 – 2010-03-15 20:10:06

2

使用lock而不是標誌來確保更新一次僅在一個線程中發生。

// class member 
private object syncObject = new object(); 

// then, in your code... 
lock(syncObject) { 
    System.Threading.Timer tmr = new System.Threading.Timer(new System.Threading.TimerCallback(Reset), null, 10, System.Threading.Timeout.Infinite); 
    datarow.other_column = value; 
} 
6

而我將與那些誰說,你應該找到另一種方式來防止無限遞歸同意,原因您的定時器不火,可能是因爲它被優化掉。最近我遇到了這個問題。

比方說,你想有一個週期定時器:

void SomeMethod() 
{ 
    Timer MyTimer = new Timer(MyTimerProc, null, 3000, 3000); 
    // other stuff goes here 
} 

現在,您運行在調試模式下,一切工作。但是當你在釋放模式下運行它時,定時器不會啓動。這是因爲它正在被優化。你需要做的是要麼保持它活着(使用GC.KeepAlive)或using

using (Timer MyTimer = new Timer(MyTimerProc, null, 3000, 3000)) 
{ 
    // other stuff here 
} 
+0

你說得對。我將計時器聲明爲表單的成員,所以它永遠不會超出範圍,現在一切正常。然而使用'使用'雖然沒有幫助。感謝解決方案。 – 2010-03-15 19:57:10

+1

不幸的是,OP並沒有將此標記爲答案,而是。 – 2011-12-20 15:19:35

+0

我同意這樣做,但我仍然不清楚爲什麼。如果我使用發佈模式進行編譯,然後使用反射器查看程序集,定時器仍然存在,那麼它在哪裏得到優化? – 2012-09-17 09:19:37