中断递归.AsParallel

时间:2015-10-23 12:33:39

标签: c# multithreading c#-4.0

我正在编写.NET 4.0 C#软件,我需要并行执行一些代码来加快工作。

我有一个Job课程,可能包含多个Job课程作为孩子 每当Job开始运行时,它都会调用Children.AsParallel.ForAll(ch => ch.Run());

我在一个单独的线程上开始工作,但是我必须使用Thread.Abort()然后Thread.Join(5000)来终止它,以确保它已经终止。

无论如何,似乎在.AsParallel()下运行的乔布斯继续正常工作......

以下是代码:

class Job
{
    public string Name;

    public List<Job> Children = new List<Job>();

    public void Run()
    {
        for(int i = 0; i < 5; i++)
        {
            int tid = Thread.CurrentThread.ManagedThreadId;
            var msg = "JOB " + Name + " " + tid;

            Debug.WriteLine(msg);
            Thread.Sleep(TimeSpan.FromSeconds(1));
        }

        Children.AsParallel().ForAll(j => j.Run());
    }
}

[TestMethod]
public void TestMultiThread()
{
    var root = new Job();
    root.Name = "A";
    root.Children = new List<Job>()
    {
        new Job() { Name = "B" },
        new Job() { Name = "C" },
    };

    var t = new Thread(() =>
    {
        try
        {
            root.Run();
        }
        catch(ThreadAbortException tae)
        {

        }
    });
    t.Start();

    Thread.Sleep(TimeSpan.FromSeconds(7));
    Debug.WriteLine("THREAD.ABORT");
    t.Abort();
    t.Join(TimeSpan.FromSeconds(5));
    Thread.Sleep(TimeSpan.FromSeconds(5));
}

这是输出:

JOB A 14
JOB A 14
JOB A 14
JOB A 14
JOB A 14
JOB B 9
JOB C 15
JOB B 9
JOB C 15
THREAD.ABORT
JOB B 9
JOB C 15
A first chance exception of type 'System.Threading.ThreadAbortException' occurred in mscorlib.dll
A first chance exception of type 'System.Threading.ThreadAbortException' occurred in Test.dll
   in System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   in System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   in System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   in System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   in System.Threading.ThreadHelper.ThreadStart()</StackTrace><ExceptionString>System.Threading.ThreadAbortException: Thread interrotto.
   in Test.Tests.OtherTests.&amp;lt;&amp;gt;c__DisplayClass14.&amp;lt;TestMultiThread&amp;gt;b__13() in Tests.cs:riga 280
   in System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   in System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   in System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   in System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   in System.Threading.ThreadHelper.ThreadStart()</ExceptionString></Exception></TraceRecord>
An exception of type 'System.Threading.ThreadAbortException' occurred in Test.dll but was not handled in user code
The thread '<No Name>' (0x14d0) has exited with code 0 (0x0).
JOB B 9
JOB C 15
JOB B 9
JOB C 15
The thread '<No Name>' (0x152c) has exited with code 0 (0x0).

有什么我错过的吗?

2 个答案:

答案 0 :(得分:1)

作为提及的评论者,您可以使用CancellationTokenSource并取消令牌。我在这里所做的就是使用Token.ThrowIfCancellationRequested来破解所有任务。

您修改过的代码 :

void Main()
{
    TestMultiThread();
}

// Define other methods and classes here
class Job
{
    public string Name;

    public List<Job> Children = new List<Job>();

    public void Run(CancellationTokenSource tokenSource)
    {
        for(int i = 0; i < 5; i++)
        {
            int tid = Thread.CurrentThread.ManagedThreadId;
            var msg = "JOB " + Name + "  " + tid +"  cnt "+  i;

            Debug.WriteLine(msg);
            Thread.Sleep(TimeSpan.FromSeconds(1));
            tokenSource.Token.ThrowIfCancellationRequested();
        }

        Children.AsParallel()
                .ForAll(j => j.Run(tokenSource));
    }
}

public void TestMultiThread()
{
    var root = new Job();
    root.Name = "A";
    root.Children = new List<Job>()
    {
        new Job() { Name = "B" },
        new Job() { Name = "C" },
    };
    CancellationTokenSource cts = new CancellationTokenSource();
    var t  =  System.Threading
                    .Tasks
                    .Task
                    .Factory.StartNew(()=> root.Run(cts),cts.Token);

    Thread.Sleep(TimeSpan.FromSeconds(7));
    Debug.WriteLine("Task Cancel requested");
    cts.Cancel();
    Debug.WriteLine("Task Canceled");
    try
    {
        t.Wait(TimeSpan.FromSeconds(5));
    }
    catch(Exception ex)
    {
        //Linqpad famous Dump method
        ex.Dump();
    }
    Thread.Sleep(TimeSpan.FromSeconds(5));
}

答案 1 :(得分:0)

不要使用Thread.Abort而是使用标志,这样您就可以控制何时完全退出作业。看看TPL文档。

https://msdn.microsoft.com/en-us/library/dd537607%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396