[英]Deadlock using manualResetEvent - c#
在我的示例 UI 中,有 3 個按鈕。 開始按鈕,暫停,恢復。 開始按鈕是 async/await 並且會調用一個方法:
private async void btnStart_Click()
{
await Task.Run(() => StartingMethod());
}
我們有一個名為_pauseEvent
的全局ManualResetEvent
。 這是StartingMethod()
的結構:
public void StartingMethod()
{
for (int i =0; i < 1000000; i++)
{
_pauseEvent.WaitOne();
// Do Something
}
}
這是暫停/恢復按鈕:
private async void btnPause_Click()
{
await Task.Run(() => _pauseEvent.Reset());
}
private async void btnResume_Click()
{
await Task.Run(() => _pauseEvent.Set());
}
但有時它會給暫停/恢復調用時的ManualResetEvent
The handle is invalid
。 這似乎是一個競爭條件問題。 所以我決定創建一個全局鎖對象。
Object _lockObject = new object();
這是新的:
public void StartingMethod()
{
for (int i =0; i < 1000000; i++)
{
lock (_lockObject)
_pauseEvent.WaitOne();
// Do Something
}
}
private async void btnPause_Click()
{
await Task.Run(() => lock (_lockObject) _pauseEvent.Reset());
}
private async void btnResume_Click()
{
await Task.Run(() => lock (_lockObject) _pauseEvent.Set());
}
但似乎,在這里,我將再次面臨鎖定對象的死鎖問題。 我該如何處理這種情況?
我很確定使用async void
、 Task.Run
和lock
會導致死鎖。 我建議做的是使用CancellationToken
和一些中間狀態來表示StartingMethod
的進度。
請注意,它不會處理許多StartingMethod
的並發執行,您需要使用CanExecute
類的CanExecute
來防止用戶連續多次單擊開始按鈕。
private int _state = 0;
public void StartingMethod(CancellationToken cancellation, bool resetState)
{
if (resetState)
{
_state = 0;
// reset your additional data
}
for (int i = _state; i < 1000000; i++)
{
if (!cancellation.IsCancellationRequested)
{
// Recover saved state
// Do Something
}
else
{
// save intermediate state
// save your additional data
_state = i;
}
}
}
我強烈建議將 try-catch 添加到async
方法中:
private CancellationTokenSource _cts;
private async Task HandleStart(bool resetState)
{
_cts = new CancellationTokenSource();
try
{
await Task.Run(() => StartingMethod(_cts.Token, resetState));
}
catch (Exception e)
{
// log or show some error on UI
}
finally
{
_cts.Dispose();
}
}
private void btnStart_Click()
{
// No need to await because it's a single statement in a method
HandleStart(true);
}
private async void btnPause_Click()
{
_cts.Cancel();
}
private void btnResume_Click()
{
HandleStart(false);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.