※ここでの外部変数argとは、MainWindowメソッドのローカル変数argのことです。
デリゲートの引数を渡す方法は、このステートメントが実行された時点での外部変数argの値が使われます。
Task.Factory.StartNew<string>(obj => ReturnArg((string)obj), arg);
しかし、直接ローカル変数を渡す方法では、ReturnArg メソッドが実行された時点での外部変数argの値が使われます。
Task.Factory.StartNew<string>(() => ReturnArg(arg));
Task.Factory.StartNewで生成されたスレッドはいずれも、最初は待機状態になっていて、しばらくたってからReturnArgメソッドが実行されます。
サンプルを実行すると、下のようになります。
ソースの記述順では、
noArgTask1 → oneArgTask1 → noArgTask2 → oneArgTask2
の順にタスクが生成されますが、各タスクの実行順は、
oneArgTask1 → oneArgTask2 → noArgTask1 → noArgTask2
になってます。また、4つのタスクの呼び出し元のスレッドは、いずれのタスクも実行される前に、各タスクの完了待ち状態になっています。 ReturnArgメソッドの実行時点での外部変数argの値を参照するタスク noArgTask1 と noArgTask2 の戻り値は、Step1、Step3ではなく、いずれもStep4 です。
MainWindow.xaml
<Window x:Class="ActionTest.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="150" Width="280">
<Grid>
<TextBlock Name="textBlock1" />
</Grid>
</Window>
MainWindow.xaml.cs
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Windows;
namespace ActionTest
{
public partial class MainWindow : Window
{
private Stopwatch sw = new Stopwatch();
public MainWindow()
{
InitializeComponent();
string arg;
sw.Start();
arg = "Step1";
Task<string> noArgTask1 = Task.Factory.StartNew<string>(() => ReturnArg(arg));
arg = "Step2";
Task<string> oneArgTask1 = Task.Factory.StartNew<string>(obj => ReturnArg((string)obj), arg);
arg = "Step3";
Task<string> noArgTask2 = Task.Factory.StartNew<string>(() => ReturnArg(arg));
arg = "Step4";
Task<string> oneArgTask2 = Task.Factory.StartNew<string>(obj => ReturnArg((string)obj), arg);
TimeSpan lastTimeSpan = sw.Elapsed;
this.textBlock1.Text =
"noArgTask1 = " + noArgTask1.Result + "\n" +
"oneArgTask1 = " + oneArgTask1.Result + "\n" +
"noArgTask2 = " + noArgTask2.Result + "\n" +
"oneArgTask2 = " + oneArgTask2.Result + "\n" +
"Last = " + lastTimeSpan;
}
private string ReturnArg(string arg)
{
return this.sw.Elapsed + " " + arg;
}
}
}
0 件のコメント:
コメントを投稿