C# · 12月 20, 2021

C#线程安全使用(四)

这是时隔多年第四篇,主要是因为身在东软受内网限制,好多文章就只好发到东软内部网站,懒的发到外面,现在一点点把在东软写的文章给转移出来。

这里主要讲解下CancellationTokenSource,CancellationTokenSource是用于取消线程,具体使用起来有点另类:首先定义实体,然后将其下的属性ToKen传递给线程,当需要取消线程时,调用下Cancel()方法。例子我依然采用了MSDN的例子,但我做了一些修改,这个例子虽然看起来挺复杂,但还是记录了许多内容。

由于不好理解,我就粗略讲解下:

Task fTask = factory.ContinueWhenAll(tasks.ToArray(),上面是创建任务,创建10个线程,并且线程中增加了判断,如果随即数等于0就取消该线程。

 再介绍下factory.ContinueWhenAll,他包含两个参数Task[] tasks,Action continuationAction。MSDN的解释是:

 方法执行 

英文解释:

CancellationTokenSource source = == = tasks = List= ( taskCtr = ; taskCtr [] values = [ ( ctr = ; ctr <= ; ctr++= rnd.Next(, (value == values[ctr </span>- <span style="color: #800080;"&gt;1</span>] =<span style="color: #000000;"&gt; value; } Console.WriteLine(</span><span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;NO Cancel at task {0}</span><span style="color: #800000;"&gt;"</span><span style="color: #000000;"&gt;,iteration); </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; values; },token)); } </span><span style="color: #0000ff;"&gt;try</span><span style="color: #000000;"&gt; { Task</span><<span style="color: #0000ff;"&gt;double</span>> fTask =<span style="color: #000000;"&gt; factory.ContinueWhenAll(tasks.ToArray(),(results) </span>=><span style="color: #000000;"&gt; { Console.WriteLine(</span><span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;Calculating overall mean…</span><span style="color: #800000;"&gt;"</span><span style="color: #000000;"&gt;); </span><span style="color: #0000ff;"&gt;long</span> sum = <span style="color: #800080;"&gt;0</span><span style="color: #000000;"&gt;; </span><span style="color: #0000ff;"&gt;int</span> n = <span style="color: #800080;"&gt;0</span><span style="color: #000000;"&gt;; </span><span style="color: #0000ff;"&gt;foreach</span> (<span style="color: #0000ff;"&gt;var</span> t <span style="color: #0000ff;"&gt;in</span><span style="color: #000000;"&gt; results) { </span><span style="color: #0000ff;"&gt;foreach</span> (<span style="color: #0000ff;"&gt;var</span> r <span style="color: #0000ff;"&gt;in</span><span style="color: #000000;"&gt; t.Result) { sum </span>+=<span style="color: #000000;"&gt; r; n</span>++<span style="color: #000000;"&gt;; } } </span><span style="color: #0000ff;"&gt;return</span> sum / (<span style="color: #0000ff;"&gt;double</span><span style="color: #000000;"&gt;)n; },token); Console.WriteLine(</span><span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;The mean is {0}.</span><span style="color: #800000;"&gt;"</span><span style="color: #000000;"&gt;,fTask.Result); } </span><span style="color: #0000ff;"&gt;catch</span><span style="color: #000000;"&gt; (AggregateException ae) { </span><span style="color: #0000ff;"&gt;foreach</span> (Exception e <span style="color: #0000ff;"&gt;in</span><span style="color: #000000;"&gt; ae.InnerExceptions) { </span><span style="color: #0000ff;"&gt;if</span> (e <span style="color: #0000ff;"&gt;is</span><span style="color: #000000;"&gt; TaskCanceledException) Console.WriteLine(</span><span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;Unable to compute mean: {0}</span><span style="color: #800000;"&gt;"</span><span style="color: #000000;"&gt;,((TaskCanceledException)e).Message); </span><span style="color: #0000ff;"&gt;else</span><span style="color: #000000;"&gt; Console.WriteLine(</span><span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;Exception: </span><span style="color: #800000;"&gt;"</span> +<span style="color: #000000;"&gt; e.GetType().Name); } } Console.ReadLine();}

}

显示结果图片,每次的结果都不一样的,所以我也是运行了好几次,看这个结果会发现一件事,线程只执行了两个,即当线程2中调用Cancel后,其他线程也被取消了。