如何在TPL中停止游戏并返回正确的值?

2 c# task-parallel-library c#-5.0

在我的TPL应用程序中,我想通过一种方法PlayTTS(string text)来播放文本到语音.

public static CancellationTokenSource cTokenSource = new CancellationTokenSource();
public static CancellationToken cToken = cTokenSource.Token;
Run Code Online (Sandbox Code Playgroud)

然后在消费者方法中.

async Task Consumer()
    {
        try
        {
            var executionDataflowBlockOptions = new ExecutionDataflowBlockOptions
            {
                MaxDegreeOfParallelism = 50,
                CancellationToken = cToken
            };
            var consumerBlock = new ActionBlock<AppointmentReminder>(
            remainder =>
            {
               if (cToken.IsCancellationRequested)
                  return;
                Dictionary<string, string> dict = new OutboundDial(ts).RunScript(remainder, cToken);
                // update UI by the returned dictionary
            },
            executionDataflowBlockOptions);

            m_bufferBlock.LinkTo(
            consumerBlock, new DataflowLinkOptions { PropagateCompletion = true });
            await consumerBlock.Completion;
        }
Run Code Online (Sandbox Code Playgroud)

我有一个按钮事件来取消该过程(WPF).

private void Cancel_Click(object sender, RoutedEventArgs e)
{
    cTokenSource.Cancel();
}
Run Code Online (Sandbox Code Playgroud)

你看,有cToken.IsCancellationRequestedActionBlock,但它并没有帮助停止处理的方法OutboundDial(ts).RunScript(remainder, cToken);,虽然我传入取消标记.

现在让我们来看看这个方法RunScript.

public Dictionary<string, string> RunScript(AppointmentReminder callData, CancellationToken cToken)
    {
        try
        {
             m_ChannelResource = m_TelephonyServer.GetChannel() as SipChannel;
             m_VoiceResource = m_ChannelResource.VoiceResource;
             // Many logging
             // Dial out

            MakeTest(callData, cToken);
        }
        catch
         {throw;}
        finally
        {
            // destroy m_ChannelResource and m_VoiceResource
         }
        return dict;
    }
Run Code Online (Sandbox Code Playgroud)

关键是MakeTest我们拥有的方法PlayTTS;

public void MakeTest(AppointmentReminder callData, CancellationToken cToken)
{
    try
    {
        if (!cToken.IsCancellationRequested)
        {
            m_VoiceResource.PlayTTS(callData.Text);  
        }
        else
        {
            cToken.ThrowIfCancellationRequested();
            m_VoiceResource.Stop(); // Stops any current activity on m_VoiceResource.
            dict["ConnectedTime"] = " no connection";
            dict["DialingResult"] = " cancellation";
        }
Run Code Online (Sandbox Code Playgroud)

m_VoiceResource.Stop()单击取消按钮时,我当前的代码没有到达.所以我的问题是何时cTokenSource.Cancel();,如何让代码运行:

m_VoiceResource.Stop(); // Stops any current activity on m_VoiceResource.
dict["ConnectedTime"] = " no connection";
dict["DialingResult"] = " cancellation";
Run Code Online (Sandbox Code Playgroud)

编辑:2014年10月31日下午1:10

根据Servy的评论,我用过 cToken.Register(() => m_VoiceResource.Stop());

我在OneDrive上创建了一个类似的演示.

Ser*_*rvy 5

在您已经检查令牌是否被取消并开始播放之后,您将取消令牌.你永远不会再回去再次执行这个条件来停下来.

你需要做的只是注册一个回调到令牌的取消,停止播放器:

cToken.Register(() => m_VoiceResource.Stop());
Run Code Online (Sandbox Code Playgroud)

只需在开始播放后立即添加注册即可.