2014-06-16 3 views
3

이벤트를 발생시켜 진행 상황을보고하는 작업자 스레드가 있습니다. Cancel 방법에서이벤트 발생 스레드가 대기하기를 기다리는 중

private volatile bool canRun; 

public void Run() 
{ 
    for (int i = 0; i < count && canRun; i++) 
    { 
     // do stuff 

     OnProgressMade((float)i/(float)count); 
    } 

    OnWorkFinished(); 
} 

public void Cancel() 
{ 
    canRun = false; 

    // wait for the thread to finish 
} 

, 나는 스레드가 끝날 때까지 기다려야하고 싶습니다. 그렇지 않으면 누군가가 Cancel으로 전화를 걸고 즉시 Dispose으로 전화를 걸고 스레드는 여전히 "작업을 수행하고 있습니다". Join을 사용하면 교착 상태가 발생할 수 있습니다. UI는 스레드가 취소 될 때까지 기다리고 스레드는 UI가 ProgressMade 이벤트를 처리 할 때까지 대기합니다.

이 문제를 해결할 방법이 있습니까, 아니면 처음부터 나쁜 디자인입니까? 현재 솔루션은 작업자를 처리하기 전에 WorkFinished 이벤트를 기다리는 UI를 사용합니다.

+2

어떤 C# 버전을 사용하고 있습니까? 이것을 기다리는 것은 그렇게하기가 어렵지 않습니다. – usr

+0

취소 방법에 가입하지 않으시겠습니까? – Vadim

+0

나는 당신의 드리프트를 잡지 못한다고 생각합니다. 'Cancel'을 호출하면 루프를 빠져 나오지 만 여전히'OnWorkFinished'를 호출합니다. 처분하고 싶지 않은 것은 무엇입니까? –

답변

2

의견에서 await을 사용할 수 있다는 힌트가 있습니다 (.NET 4.0에서도 가능). 그것은 다음과 같이 수 :

MyWorker w; 
CancellationTokenSource cts; 

void OnStart(eventargs bla bla) { 
cts = new ...(); 
w = new ...(cts.Token); 
} 

void OnCancel(eventargs bla bla) { 
cts.Cancel(); 
await w.WaitForShutdown(); 
MsgBox("cancelled"); 
} 

그리고 우리는 MyWorker 협력 할 필요가 :

class MyWorker { 
CancellationToken ct = <from ctor>; 
TaskCompletionSource<object> shutdownCompletedTcs = new ...(); 

public void Run() 
{ 
    for (int i = 0; i < count && !ct.IsCancellationRequested; i++) 
    { 
     // do stuff 

     OnProgressMade((float)i/(float)count); 
    } 

    //OnWorkFinished(); //old 
    shutdownCompletedTcs.SetResult(null); //new, set "event" 
} 

public Task WaitForShutdown() { 
return shutdownCompletedTcs.Task; 
} 
} 

가 (빨리 함께 때렸다.) 참고, 모든 작업이 기다리고 사용이 나올 때까지 기다리는 것이. 컨트롤 흐름을 방해하지 않으면 서 UI 스레드를 해제합니다.

또한 MyWorker은 협조적으로 취소 가능합니다. 그것은 UI에 대해 아무것도 모릅니다.

+1

+1 : 그래, 나는 매번 취소 토큰 기반 접근법에 투표 ​​할 것입니다. – code4life

+0

이것은 내가 원하는만큼 정확하게 작동합니다. 고맙습니다. –

관련 문제