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

时间:2014-10-29 14:52:38

标签: c# task-parallel-library c#-5.0

在我的TPL应用程序中,我希望通过PlayTTS(string text)方法播放文本到语音。

public static CancellationTokenSource cTokenSource = new CancellationTokenSource();
public static CancellationToken cToken = cTokenSource.Token;

然后在消费者方法中。

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;
        }

我有一个取消流程的按钮事件(WPF)。

private void Cancel_Click(object sender, RoutedEventArgs e)
{
    cTokenSource.Cancel();
}

您看到cToken.IsCancellationRequested中有ActionBlock,但是虽然我已经传入了取消令牌,但它无法在方法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;
    }

关键点是方法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";
        }

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

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

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

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

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

2 个答案:

答案 0 :(得分:5)

在您检查了令牌是否被取消并开始播放后,您取消了令牌。你永远不会再回去再次执行这个条件来停止。

您需要做的只是注册一个回调令牌的取消,以阻止玩家:

cToken.Register(() => m_VoiceResource.Stop());

只需在开始游戏后立即添加注册即可。

答案 1 :(得分:0)

最后,我在Microsoft MVP的帮助下找到了解决方案。 Servy的解决方案很漂亮,但有缺陷。

cToken.Register(() => m_VoiceResource.Stop());

注册应该在开始播放之前而不是之后进行。

编辑: 2014年11月10日上午8:09

更好的一个:

 cToken.Register(() => m_VoiceResource.Stop());
 return;