使用 Task.Factory.StartNew() 然后 Return 值
Using Task.Factory.StartNew() Then Return Value
我有一个 class,其中有一些已创建和发生的任务。当我 运行 我的测试应用程序的线程示例 created/used 如下...
- Thread9(主线程)
- 线程 9
- 线程 9
- 线程 10(工人启动新线程)
- Thread11(工人 ContinueWith 线程)
- 线程 11
我能够将一个对象从我的主线程 (9) 传递到工作线程 (10),然后从工作线程传递到工作线程 ContinueWith 线程(11) [也就是完成工作线程 (10) )]。除了一个例外,我所做的一切都很好......我似乎无法使用事件之类的东西将该对象返回到主线程。每当我尝试委托或调用回主线程时,它都不会工作。它总是在 Thread11 而不是 Thread9 上触发!
我的目标是将对象(在 Thread11 中使用)返回到主 Thread9。
备注:
- 我无法使用 .Wait() 或以任何方式暂停 MainUI。
- 我不能使用 Task.WaitAll() 或 Task.WaitAny(),因为它也会冻结 UI。
- 调用将不起作用,因为这是自定义 class 而不是表单。
已更新 - 示例:
private SQLConnectionProperties sql = new SQLConnectionProperties();
private void SQLTest()
{
//Being called from main UI thread 9
sql.SQLErrorMessage = "FIRST CHANGE";
Task<SQLConnectionProperties> taskConnect = Task.Factory
.StartNew(() => threadConnect(sql), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default)
.ContinueWith((task) => threadConnect(task.Result, true));
//Continue back to main UI (still in main UI thread 9)
}
private SQLConnectionProperties threadConnect(SQLConnectionProperties sql, bool bContinuation = false)
{
if (!bContinuation)
{
//In new thread 10
sql.SQLErrorMessage = "SECOND CHANGE";
}
else
{
//In new thread 11
sql.SQLErrorMessage = "THIRD CHANGE";
}
return sql;
}
使用上面的代码,我将拥有我想要的一切,直到 In new thread 11
行。 SQLErrorMessage 更改为 "THIRD CHANGE" 并返回后,我需要引发某种类型的事件或将结果返回到主 UI 线程 9.
您需要使用 _synchronizationContext.Send
或 _synchronizationContext.Post
与 UI 线程通信。
此外,根据您提到的情况,我认为您在调用上述任一函数时还需要传递 "false",以便它知道该函数不是从 UI 线程调用的。
_synchronizationContext = SynchronizationContext.Current
正如@r00tdev 所解释的那样,使用 SynchronizationContext() class 是我尝试做的事情的解决方案。下面您将看到我如何使用它来将工作线程的结果返回到主 UI 线程的示例。感谢@r00tdev 的回答!
示例:
private void SQLTest()
{
//Set up a sync context back to this main UI thread
m_sql.SyncContext = SynchronizationContext.Current;
//Being called from main UI thread 9
m_sql.SQLErrorMessage = "FIRST CHANGE";
Task<SQLConnectionProperties> taskConnect = Task.Factory
.StartNew(() => threadConnect(m_sql), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default)
.ContinueWith((task) => threadConnect(task.Result, true));
//Continue back to main UI (still in main UI thread 9)
}
private SQLConnectionProperties threadConnect(SQLConnectionProperties sql, bool bContinuation = false)
{
if (!bContinuation)
{
//In new thread 10
sql.SQLErrorMessage = "SECOND CHANGE";
}
else
{
//In new thread 11
sql.SQLErrorMessage = "THIRD CHANGE";
sql.SyncContext.Post(threadConnectComplete, sql);
}
return sql;
}
private void threadConnectComplete(object state)
{
//Back in the main UI thread! Save the changes to the sql object
SQLConnectionProperties sql = state as SQLConnectionProperties;
m_sql = sql;
//See the results and use this area to update the main UI
Debug.WriteLine("SQLErrorMessage:" + sql.SQLErrorMessage);
//TESTING NON THREAD SAFE just to show you no runtime errors happen
form_MainUI.textbox1.Text = sql.SQLErrorMessage;
}
我有一个 class,其中有一些已创建和发生的任务。当我 运行 我的测试应用程序的线程示例 created/used 如下...
- Thread9(主线程)
- 线程 9
- 线程 9
- 线程 10(工人启动新线程)
- Thread11(工人 ContinueWith 线程)
- 线程 11
我能够将一个对象从我的主线程 (9) 传递到工作线程 (10),然后从工作线程传递到工作线程 ContinueWith 线程(11) [也就是完成工作线程 (10) )]。除了一个例外,我所做的一切都很好......我似乎无法使用事件之类的东西将该对象返回到主线程。每当我尝试委托或调用回主线程时,它都不会工作。它总是在 Thread11 而不是 Thread9 上触发!
我的目标是将对象(在 Thread11 中使用)返回到主 Thread9。
备注:
- 我无法使用 .Wait() 或以任何方式暂停 MainUI。
- 我不能使用 Task.WaitAll() 或 Task.WaitAny(),因为它也会冻结 UI。
- 调用将不起作用,因为这是自定义 class 而不是表单。
已更新 - 示例:
private SQLConnectionProperties sql = new SQLConnectionProperties();
private void SQLTest()
{
//Being called from main UI thread 9
sql.SQLErrorMessage = "FIRST CHANGE";
Task<SQLConnectionProperties> taskConnect = Task.Factory
.StartNew(() => threadConnect(sql), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default)
.ContinueWith((task) => threadConnect(task.Result, true));
//Continue back to main UI (still in main UI thread 9)
}
private SQLConnectionProperties threadConnect(SQLConnectionProperties sql, bool bContinuation = false)
{
if (!bContinuation)
{
//In new thread 10
sql.SQLErrorMessage = "SECOND CHANGE";
}
else
{
//In new thread 11
sql.SQLErrorMessage = "THIRD CHANGE";
}
return sql;
}
使用上面的代码,我将拥有我想要的一切,直到 In new thread 11
行。 SQLErrorMessage 更改为 "THIRD CHANGE" 并返回后,我需要引发某种类型的事件或将结果返回到主 UI 线程 9.
您需要使用 _synchronizationContext.Send
或 _synchronizationContext.Post
与 UI 线程通信。
此外,根据您提到的情况,我认为您在调用上述任一函数时还需要传递 "false",以便它知道该函数不是从 UI 线程调用的。
_synchronizationContext = SynchronizationContext.Current
正如@r00tdev 所解释的那样,使用 SynchronizationContext() class 是我尝试做的事情的解决方案。下面您将看到我如何使用它来将工作线程的结果返回到主 UI 线程的示例。感谢@r00tdev 的回答!
示例:
private void SQLTest()
{
//Set up a sync context back to this main UI thread
m_sql.SyncContext = SynchronizationContext.Current;
//Being called from main UI thread 9
m_sql.SQLErrorMessage = "FIRST CHANGE";
Task<SQLConnectionProperties> taskConnect = Task.Factory
.StartNew(() => threadConnect(m_sql), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default)
.ContinueWith((task) => threadConnect(task.Result, true));
//Continue back to main UI (still in main UI thread 9)
}
private SQLConnectionProperties threadConnect(SQLConnectionProperties sql, bool bContinuation = false)
{
if (!bContinuation)
{
//In new thread 10
sql.SQLErrorMessage = "SECOND CHANGE";
}
else
{
//In new thread 11
sql.SQLErrorMessage = "THIRD CHANGE";
sql.SyncContext.Post(threadConnectComplete, sql);
}
return sql;
}
private void threadConnectComplete(object state)
{
//Back in the main UI thread! Save the changes to the sql object
SQLConnectionProperties sql = state as SQLConnectionProperties;
m_sql = sql;
//See the results and use this area to update the main UI
Debug.WriteLine("SQLErrorMessage:" + sql.SQLErrorMessage);
//TESTING NON THREAD SAFE just to show you no runtime errors happen
form_MainUI.textbox1.Text = sql.SQLErrorMessage;
}