通常问题是主线程等待子线程,我可以在await
上使用Task
。
但我有一种情况,子线程必须等待主线程中的某些方法完成才能继续。如何使这种沟通成为可能?
public void MainThread()
{
Task t = Task.Run(ChildThread); //not using await because we want to continue doing work that must be only on the main thread
WorkA();
WorkB();
???
WorkC();
}
public async Task ChildThread()
{
WorkD();
???
Need_WorkB_ToBeCompletedBeforeThisOne();
}
WorkA
WorkB
WorkC
都必须位于主线程上。所有这些都将在我的实际代码中间接地从子线程中发出,因为子线程需要它们完成但由于线程限制而无法执行它。
我有一种让我的子线程告诉主线程已经完成工作的方法(所以我将代码简化为你在这里看到的,一旦任务开始工作将立即紧随其后)但我需要一些方法来发行者(子线程)了解这些命令的进度。
PS。感谢来自这个线程的回答,我为Unity创建了CoroutineHost
,你可以await
yield IEnumerator
方法,你可以从你的主线程发出任何你的子线程:https://github.com/5argon/E7Unity/tree/master/CoroutineHost
答案 0 :(得分:4)
你正在寻找一个“信号”。由于子节点是异步的,并且信号只使用一次,TaskCompletionSource<T>
可以很好地工作:
public void MainThread()
{
var tcs = new TaskCompletionSource<object>(); // Create the signal
Task t = Task.Run(() => ChildThread(tcs.Task)); // Pass the "receiver" end to ChildThread
WorkA();
WorkB();
tcs.SetResult(null); // Send the signal
WorkC();
}
public async Task ChildThread(Task workBCompleted)
{
WorkD();
await workBCompleted; // (asynchronously) wait for the signal to be sent
Need_WorkB_ToBeCompletedBeforeThisOne();
}
有关详细信息,请参阅my book中的食谱11.4“异步信号”。如果您需要多次设置和取消设置的“信号”,则应使用AsyncManualResetEvent
。
答案 1 :(得分:1)
如果WorkB是一个任务,我会想象这样的事情:
public void MainThread()
{
Task workB = WorkB();
ChildThread(workB); // you don't need to use Task.Run here, the task is ran automatically
WorkA();
WorkC();
}
public async Task ChildThread(Task otherTaskToWait)
{
WorkD();
await otherTaskToWait;
Need_WorkB_ToBeCompletedBeforeThisOne();
}