多线程跨类取消与TPL [英] Multi-Threading Cross-Class Cancellation with TPL

查看:175
本文介绍了多线程跨类取消与TPL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所有的,我有我的后台线程(与取消支持)运行使用任务Paralell库(TPL)一个长期运行的进程。这个长期运行的TAKS的代码包含类验证中,当方法

All, I have a long running process that I run on a background thread (with cancellation support) using the Task Paralell Library (TPL). The code for this long running taks is contained within Class Validation, and when the method

public bool AsyncRunValidationProcess(TaskScheduler _uiScheduler, 
    CancellationToken _token, dynamic _dynamic = null)
{
    try
    {

        // Note: _uiScheduler is used to update the UI thread with progress infor etc.

        for (int i = 0; i < someLargeLoopNumber; i++)
        {
            // Cancellation requested from UI Thread.
            if (_token.IsCancellationRequested) 
                _token.ThrowIfCancellationRequested();
        }
        return true;
    }
    catch (Exception eX)
    {
        // Do stuff. Display `eX` if cancellation requested.
        return false;
    }
}



运行级验证我可以取消该过程罚款。取消请求是通过适当的委托办理(如下图所示),并能正常工作(我不相信的,这是我的问题的原因)。

is run from Class Validation I can cancel the process fine. The cancellation request is handled by the appropriate delegate (shown below) and this works fine (I don't belive this is the cause of my problem).

当我从另一个类运行此方法,类批次,我通过控制的方法做到这一点。

When I run this method from another class, Class Batch, I do this via a "controller" method

asyncTask = Task.Factory.StartNew<bool>(() => asyncControlMethod(), token);



这反过来又调用方法

which in turn invokes the method

valForm.AsyncRunValidationProcess(uiScheduler, token, 
    new List<string>() { strCurrentSiteRelPath }));



其中, valForm 是我的访问到类验证,方法运行良好,但是当我尝试注销代表

where valForm is my accessor to Class Validation, the method runs fine, but when I attempt a cancellation the delegate

cancelHandler = delegate 
{
    UtilsTPL.CancelRunningProcess(asyncTask, cancelSource);
};



其中,

where

public static void CancelRunningProcess(Task _task, 
    CancellationTokenSource _cancelSource)
{
    try
    {
        _cancelSource.Cancel();
        _task.Wait(); // On cross-class call it freezes here.
    }
    catch (AggregateException aggEx)
    {
        if (aggEx.InnerException is OperationCanceledException)
            Utils.InfoMsg("Operation cancelled at users request.");
        if (aggEx.InnerException is SqlException)
            Utils.ErrMsg(aggEx.Message);
    }
}



冻结/挂起(没有未处理的异常等)在 _task.Wait()。这(我相信 - 通过测试)是事实,我取消 asyncControlMethod()已叫 valForm.AsyncRunValidationProcess(做... ),因此它被取消 asyncControlMethod()这是造成当前进程挂起。这个问题似乎与传递 CancellationTokenSource 等来了孩子的方法。在 IsCancellationPending 事件触发,并杀死控制方法,这会导致孩子的方法挂起。

freezes/hangs (with no unhandled exception etc.) on _task.Wait(). This (I belive - through testing) is to do with the fact that I am cancelling asyncControlMethod() which has called valForm.AsyncRunValidationProcess(...), so it is cancelling asyncControlMethod() which is causing the current process to hang. The problem seems to be with passing the CancellationTokenSource etc. to the child method. The IsCancellationPending event fires and kills the controlling method, which causes the child method to hang.

CAN谁能告诉我什么,我做错了或者(更贴切),我应该怎么做,让这样的撤销程序

?注意:我试图生成一个子任务运行 valForm.AsyncRunValidationProcess(...),有自己的的CancellationToken ,但这并没有奏效。

Note: I have tried to spawn a child task to run valForm.AsyncRunValidationProcess(...), with its own CancellationToken but this has not worked.

感谢您的时间。

推荐答案

回答这个问题(由嘉积武的评论和链接大量帮助)是,你不能声明的CancellationToken 作为传递给级联方式的全局变量;也就是说,你不能有

The answer to this problem (helped massively by Jiaji Wu's comment and link) was that you cannot declare the CancellationToken as a global variable that is passed to the cascading methods; that is, you cannot have

public class MainClass
{
    private CancellationTokenSource = source;
    private CancellationToken token;

    public MainClass()
    {
        source = new CancellationtokenSource();
        token = source.Token;
    }

    private void buttonProcessSel_Click(object sender, EventArgs e)
    {
        // Spin-off MyMethod on background thread.
        Task<bool> asyncControllerTask = null;
        TaskSpin(asyncControllerTask, cancelSource, token, MyMethod);
    }

    private void method()
    {
        // Use the global token DOES NOT work!
        if (token.IsCancellationRequested)      
            token.ThrowIfCancellationRequested();
    }

    private void TaskSpin(Task<bool> asyncTask, CancellationTokenSource cancelSource,
        CancellationToken token, Func<bool> asyncMethod)
    {
        try
        {
            token = cancelSource.Token;
            asyncTask = Task.Factory.StartNew<bool>(() => asyncMethod(token), token);

            // To facilitate multitasking the cancelTask ToolStripButton
            EventHandler cancelHandler = null;
            if (cancelSource != null)
            {
                cancelHandler = delegate
                {
                    UtilsTPL.CancelRunningProcess(mainForm, uiScheduler, asyncTask, cancelSource, true);
                };
            }

        // Callback for finish/cancellation.
            asyncTask.ContinueWith(task =>
            {
                // Handle cancellation etc.
            }

            // Other stuff...
        }
    }
}

在maethod运行

使用全球令牌在后台线程DOEN不行!该方法必须明确通过标记为它能够注册。我不知道确切的原因,这是如此,但我知道在未来,现在你需要将令牌传递给的MyMethod()像这样

Use of the global token in the maethod run on the background thread doen NOT work! The method must be explicitly passed the token for it to be able to register it. I am not sure of the exact reason why this is the case, but I will know in future, now you need to pass the token to MyMethod() like this

    private void method(CancellationToken token)
    {
        // Use the global token DOES NOT work!
        if (token.IsCancellationRequested)      
            token.ThrowIfCancellationRequested();
    }

我希望这可以帮助别人

这篇关于多线程跨类取消与TPL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆