首页 > 解决方案 > 执行正则表达式时 CancellationSource 不起作用

问题描述

在处理某些文件时,我有一个Regex可能导致死循环的问题。尽管我迟早会解决这个问题,但为了安全起见,我想在可取消的任务中运行它。

我在这里阅读了一些答案,但以下解决方案均无效。有什么帮助吗?

    public static Task<CodeFile> CreateCodeFile(string fileName)
    {
        var fileInfo = new FileInfo(fileName);
        foreach (var codeFileFactory in CodeFileFactories)
        {
            var cancellationTokenSource = new CancellationTokenSource();
            cancellationTokenSource.CancelAfter(1000);
            var task = new Task<CodeFile>(() => TryToCreateCodeFile(codeFileFactory, fileInfo),
                cancellationTokenSource.Token);
            task.RunSynchronously(); //Get lost here.
            if (!task.Wait(1000))
                cancellationTokenSource.Cancel();
            
            File.WriteAllTextAsync("FailedLog.txt",
                File.ReadAllTextAsync("FailedLog.txt") + "\r\n" + fileName);
            cancellationTokenSource.Dispose();
            return task;
        }

        return null;
    }

或者:

    public static async Task<CodeFile> CreateCodeFile(string fileName)
    {
        var fileInfo = new FileInfo(fileName);
        foreach (var codeFileFactory in CodeFileFactories)
        {
            var cancellationTokenSource = new CancellationTokenSource();
    
            try
            {
                cancellationTokenSource.CancelAfter(1000);
                var codeFile = await Task.Run(() => TryToCreateCodeFile(codeFileFactory, fileInfo), 
                    cancellationTokenSource.Token); //Get lost here.
                if (codeFile != null)
                    return codeFile;
            }
            catch (TaskCanceledException)
            {
                File.WriteAllTextAsync("FailedLog.txt",
                    File.ReadAllTextAsync("FailedLog.txt") + "\r\n" + fileName);
            }
            finally
            {
                cancellationTokenSource.Dispose();
            }
        }
    
        return null;
    }

这是要调用的函数:

    private static CodeFile TryToCreateCodeFile(ICodeFileFactory codeFileFactory, FileInfo fileInfo)
    {
        var codeFile = codeFileFactory.CreateByName(fileInfo);
        return codeFile;
        //Somewhere deeper, .net Regex.Matches() caused the dead loop which I cannot control.
    }

在这个主题CancellationTokenSource.CancelAfter not working中,我读到了类似“您的睡眠方法正在忽略 CancellationToken”之类的内容。我的情况会发生这种情况吗?

标签: c#task-parallel-librarycancellationtokensourcecancellation-token

解决方案


取消令牌实现合作取消,这意味着被“取消”的代码必须通过积极检查令牌的状态来进行合作。Regex.Matches没有接受令牌的重载,这意味着它不能以这种方式取消。

一般来说,任务不能被神奇地取消。任务执行的代码必须明确地执行此操作(使用类似的东西token.ThrowIfCancellationRequested()),您的代码不会这样做,因此令牌不会做任何有用的事情。将令牌传递给Task.Run记录如下:

如果工作尚未开始,可用于取消工作的取消标记。Run(Action, CancellationToken) 不会将 cancelToken 传递给 action。

所以是的,如果任务没有开始,那将取消它,在你的情况下不是很有用。

如果您执行一些不接受和处理取消令牌的长时间运行的操作(并且您无法自己处理取消,通过不时检查令牌) - 那么您无法使用它们取消它。

在你的情况下,我建议Regex.MatchTimeout


推荐阅读