私のアプリケーションは、次のコードを使用して長時間実行されるタスクをスケジュールします。
Task.Factory.StartNew<bool>((a) => WorkTask1(),
TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent)
.ContinueWith(antecedent => WorkCompletedTask1(antecedent.Result),
TaskScheduler.FromCurrentSynchronizationContext());
WorkCompletedTask1がスケジュールされ、期待どおりにUIに結果が表示されます。WorkTask1の結果に応じて、WorkCompletedTask1は次のステートメントを使用して追加のタスクをスケジュールする場合があります。
Task.Factory.StartNew<bool>((a) => WorkTask2(),
TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent)
.ContinueWith(antecedent => WorkCompletedTask2(antecedent.Result),
TaskScheduler.FromCurrentSynchronizationContext());
WorkTask2は、期待どおりに別のスレッドで実行されません。WorkTask2が完了するまでブロックされるUIスレッドで実行されます。TaskCreationOptions.LongRunningは別のスレッドを保証すると思いました。
これが機能しない理由について何か提案はありますか?UIの.continuewithタスクからではなく、UIタスクと非UIタスクから追加タスクをスケジュールできます。
壊れたサンプルプロジェクトコード
フォームにボタンがある空のWindowsフォームプロジェクトでbutton1
は、このコードは期待どおりに機能しません(Windows 7 VS2010 Express Net4.0)。T2とT3は、ワーカースレッドではなく、UIスレッドで実行されます。button1フォームにlistBox1を追加して、次のことを試してください。
private delegate void DelegateSendMsg(String msg);
private DelegateSendMsg m_DelegateSendMsg;
private TaskScheduler uiSched;
private Process thisProcess;
private string
thisProcessName,
thisProcessId,
uiThreadName,
nonuiStatus = "Non-UI",
uiStatus = "UI";
private void Form1_Load(object sender, EventArgs e)
{
thisProcess = Process.GetCurrentProcess();
thisProcessName = thisProcess.ProcessName;
thisProcessId = thisProcess.Id.ToString();
uiThreadName = CurrentThread;
m_DelegateSendMsg = this.SendMsg;
uiSched = TaskScheduler.FromCurrentSynchronizationContext();
SendMsg("UI thread name is " + CurrentThread);
}
//create the name of the current task
public string CurrentThread
{
get
{
string threadId = null;
if (String.IsNullOrEmpty(Thread.CurrentThread.Name))
threadId = thisProcess.Id.ToString() + "=" + thisProcessName;
else
threadId = thisProcessId
+ "=" + thisProcessName
+ "/" + Thread.CurrentThread.Name;
threadId += ":" + Thread.CurrentThread.ManagedThreadId + " ";
return threadId;
}
}
//validate if the function is running in the expected UI state or not
public bool MeetsUIExpectations(string functionName, string expectedStatus)
{
bool rc = true;
string currentThreadName = CurrentThread;
string text =
"Function " + functionName + " running in thread " + currentThreadName;
if ((currentThreadName == uiThreadName) & expectedStatus == uiStatus)
text += ": UI status as expected";
else if ((currentThreadName != uiThreadName) & expectedStatus == nonuiStatus)
text += ": non-UI status as expected";
else
{
text += ": UI status is NOT as expected!"
+ " Expected: " + expectedStatus
+ "; running in thread" + currentThreadName;
rc = false;
}
SendMsg(text);
return rc;
}
//display a single text message
private void SendMsg(String msg)
{
if (this.InvokeRequired)
try { this.Invoke(m_DelegateSendMsg, "UI context switch: " + msg); }
catch (Exception) { }
else
{
listBox1.Items.Add(msg);
listBox1.TopIndex = listBox1.Items.Count - 1;
}
}
private void button1_Click(object sender, EventArgs e)
{
Task.Factory.StartNew<bool>((a) =>
T1(), TaskScheduler.Default,
TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent)
.ContinueWith(antecedent => T1Completed(antecedent.Result), uiSched);
}
private bool T1()
{
//get the name of the currently running function and validate UI status
var currentMethod = System.Reflection.MethodInfo.GetCurrentMethod();
MeetsUIExpectations(currentMethod.ToString(), nonuiStatus);
int i = 0;
while (i < Int32.MaxValue) i++;
return true;
}
private void T1Completed(bool successful)
{
var currentMethod = System.Reflection.MethodInfo.GetCurrentMethod();
MeetsUIExpectations(currentMethod.ToString(), uiStatus);
if (successful)
{
Task.Factory.StartNew<bool>((a) =>
T2(), TaskScheduler.Default,
TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent)
.ContinueWith(antecedent => T2Completed(antecedent.Result), uiSched);
}
}
private bool T2()
{
var currentMethod = System.Reflection.MethodInfo.GetCurrentMethod();
MeetsUIExpectations(currentMethod.ToString(), nonuiStatus);
int i = 0;
while (i < Int32.MaxValue) i++;
return true;
}
private void T2Completed(bool successful)
{
var currentMethod = System.Reflection.MethodInfo.GetCurrentMethod();
MeetsUIExpectations(currentMethod.ToString(), uiStatus);
Task.Factory.StartNew<bool>((a) =>
T3(), TaskScheduler.Default,
TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent)
.ContinueWith(antecedent => T3Completed(antecedent.Result), uiSched);
}
private bool T3()
{
var currentMethod = System.Reflection.MethodInfo.GetCurrentMethod();
MeetsUIExpectations(currentMethod.ToString(), nonuiStatus);
int i = 0;
while (i < Int32.MaxValue) i++;
return true;
}
private void T3Completed(bool successful)
{
//get the name of the currently running function and validate UI status
var currentMethod = System.Reflection.MethodInfo.GetCurrentMethod();
MeetsUIExpectations(currentMethod.ToString(), uiStatus);
SendMsg("All functions completed");
}