2

누군가 나를 도울 수 있으면 제발. TPL 연결된 취소 토큰을 사용하려고합니다. 문제는 주 CancellationTokenSource를 취소 한 후 연결된 토큰의 속성 IsCancellationRequested 값이 여전히 "거짓"입니다.C# 작업 - 연결된 취소 토큰이 작동하지 않습니다.

나는 확실히 두 가지 일을 시작하지만, 똑같은 것이어야합니다. 처음에는 CancellationToken을 전달하고, 두 번째로는 CancellationTokenSource를 전달합니다. 문제는 동일합니다 : while 루프에서 - 조건 linkedToken.IsCancellationRequested는 취소 후 "false"로 유지됩니다.

public class Manager 
{ 
    private Task tokenTask; 
    private Task sourceTask; 
    private CancellationTokenSource mainCancelationTokenSource; 
    private CancellationToken mainToken; 

    public Manager() 
    { 
     this.mainCancelationTokenSource = new CancellationTokenSource(); 
     this.mainToken = mainCancelationTokenSource.Token; 
     this.mainToken.Register(MainCanceled); 
    } 

    public void Start() 
    { 
     Workers w = new Workers(); 
     tokenTask = Task.Run(() => w.DoWorkToken(mainToken), mainToken); 
     sourceTask = Task.Run(() => w.DoWorkSource(mainCancelationTokenSource), mainCancelationTokenSource.Token); 

    } 
    public void Cancel() 
    { 
     mainCancelationTokenSource.Cancel(); 
    } 

    private void MainCanceled() 
    { 
     try 
     { 
      tokenTask.Wait(); 
     } 
     catch (Exception e) 
     { 

     } 

     try 
     { 
      sourceTask.Wait(); 
     } 
     catch (Exception e) 
     { 

     } 
    } 
} 

class Workers 
{ 
    public void DoWorkToken(CancellationToken mainToken) 
    { 
     CancellationTokenSource linkedCts = CancellationTokenSource.CreateLinkedTokenSource(mainToken); 
     CancellationToken linkedToken = linkedCts.Token; 

     while (!linkedToken.IsCancellationRequested) 
     { 
      Random r = new Random(); 
      Task.Delay(200 * r.Next(1, 11)).Wait(); 
     } 

     linkedToken.ThrowIfCancellationRequested(); 
    } 

    public void DoWorkSource(CancellationTokenSource mainCts) 
    { 
     CancellationTokenSource linkedCts = CancellationTokenSource.CreateLinkedTokenSource(mainCts.Token); 

     while (!linkedCts.Token.IsCancellationRequested) 
     { 
      Random r = new Random(); 
      Task.Delay(200 * r.Next(1, 11)).Wait(); 
     } 

     linkedCts.Token.ThrowIfCancellationRequested(); 
    } 
} 

는 콘솔 응용 프로그램 Main 메서드에서이 코드를 시작하려면 :

class Program 
{ 
    static void Main(string[] args) 
    { 
      Manager manager = new Manager(); 
      manager.Start(); 
      //Console.ReadKey(); 

      Thread.Sleep(5000); 
      manager.Cancel(); 
    } 
} 

여러분의 도움에 감사드립니다 여기

내가 사용하고있는 코드입니다! 당신은 토큰이 취소 될 때 실행할 콜백을 등록

this.mainToken.Register(MainCanceled); 

:

답변

5

이 문제의 원인이 라인입니다. 내부적으로 콜백은 부모 CancellationTokenSource에게 위임되며 소스 취소가 요청 될 때 실행할 콜백 목록에 배치됩니다. 해당 처리기에서 수행

tokenTask.Wait(); 
sourceTask.Wait(); 

따라서이 콜백은 관련 작업이 완료 될 때까지 완료되지 않습니다. 이 작업에서는 취소가 요청 될 때까지이

while (!linkedToken.IsCancellationRequested) { 
    // loop here 
} 

이 그래서 작업이 완료되지 않습니다. 이제 까다로운 부분에

: 그것은 또한 부모 (mainToken) 토큰 소스 목록에 콜백을 넣어 합니다

CancellationTokenSource.CreateLinkedTokenSource(mainToken) 

당신이 연결 만들 토큰 소스. 이 콜백이 실행되면 링크 된 토큰 소스도 역시 취소됩니다. 이 콜백은 콜백 이후에 이 될 것입니다.

첫 번째 콜백 (사용자)이 완료 될 때까지 기다리기 때문에 태스크는 링크 된 토큰 IsCancellationRequested가 true가 될 때까지 대기하고 링크 된 토큰 소스는 자신의 콜백이 완료 될 때까지 기다리고이 플래그를 설정하기를 기다립니다.

그냥 콜백을 제거 또는 방법으로 그것을 쓰기가 완료 될 때까지 관련 작업 대기를 방해하지 않는, 또는 연결 토큰 소스 IsCancellationRequested 플래그를 기다릴하는 작업을 변경,이 문제를 해결합니다.

+0

답장을 보내 주셔서 감사합니다. 콜백을 제거하면 모든 것이 작동합니다. 하지만 분명히하기 위해 while 루프의 조건을 변경했습니다 : while (! mainToken.IsCancellationRequested). (이것은 취소 된 소스의 토큰입니다. 반면에 루프는 각각 소스와 함께 조건을 넣습니다). 콜백을 다시 추가했습니다. 이 토큰은 취소되고 작업은 끝나고 콜백이 끝나면 모든 것이 작동합니다. 링크 된 소스가이 "콜백"목록에 있다고 결론을 내릴 수 있지만 소스 자체는 등록 된 콜백에도 불구하고 취소됩니까? – Thomas

+0

@ 토마스 당신 말이 맞아요. 나는 부분적으로 틀렸어. 내 대답을 업데이트 했어. – Evk

+0

답장을 다시 한번 보내 주셔서 감사합니다. – Thomas