C# 子线程如何等待主线程中的某些内容完成?

C# 子线程如何等待主线程中的某些内容完成?,c#,multithreading,task-parallel-library,C#,Multithreading,Task Parallel Library,通常问题是主线程等待子线程,我可以在任务上使用wait 但是我有一种情况,子线程必须等待主线程中的某个方法完成后才能继续。如何使这种交流成为可能 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(); Wor

通常问题是主线程等待子线程,我可以在
任务上使用
wait

但是我有一种情况,子线程必须等待主线程中的某个方法完成后才能继续。如何使这种交流成为可能

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
都必须位于主线程上。在我的实际代码中,所有这些问题都是从子线程间接发出的,因为子线程需要完成它们,但由于线程限制而无法完成

我有一种方法让我的子线程告诉主线程已经开始工作了(因此我将代码简化为您在这里看到的,只要任务开始,工作就会立即进行),但是我需要一些方法让发布者(子线程)知道这些命令的进度


另外,由于这个线程的回答,我为Unity创建了
CoroutineHost
,您可以
等待
从您的任何子线程向您的主线程发出的
yield IEnumerator
方法:

如果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();
}

如果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();
}
你在寻找一个“信号”。由于子级是异步的,并且信号只使用一次,因此
TaskCompletionSource
可以很好地工作:

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();
}
public void主线程()
{
var tcs=new TaskCompletionSource();//创建信号
Task t=Task.Run(()=>ChildThread(tcs.Task));//将“receiver”端传递给ChildThread
WorkA();
WorkB();
SetResult(null);//发送信号
WorkC();
}
公共异步任务子线程(任务工作已完成)
{
WorkD();
等待工作完成;//(异步)等待发送信号
需要在此之前完成工作();
}
有关更多信息,请参阅中的配方11.4“异步信号”。如果您需要一个可以多次设置和取消设置的“信号”,那么您应该使用。

您正在寻找一个“信号”。由于子级是异步的,并且信号只使用一次,因此
TaskCompletionSource
可以很好地工作:

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();
}
public void主线程()
{
var tcs=new TaskCompletionSource();//创建信号
Task t=Task.Run(()=>ChildThread(tcs.Task));//将“receiver”端传递给ChildThread
WorkA();
WorkB();
SetResult(null);//发送信号
WorkC();
}
公共异步任务子线程(任务工作已完成)
{
WorkD();
等待工作完成;//(异步)等待发送信号
需要在此之前完成工作();
}

有关更多信息,请参阅中的配方11.4“异步信号”。如果您需要一个可以多次设置和取消设置的“信号”,那么您应该使用。

为什么不让
ChildThread()
只执行
WorkD()
并返回,然后在
MainThread()
中调用
need\u WorkB…()
?我的错,实际上,WorkA到C将由
ChildThread()
发出(因为如果WorkA到C是在主线程以外的线程上执行的,则存在软件限制)。我需要一种方法,以便在发出后,
ChildThread()
可以获得主线程中情况的某种指示。为什么不使用
ChildThread())
只做
WorkD()
并返回,然后
MainThread()
中等待WorkB()
并调用
Need\u WorkB…()
之后?我糟糕的,实际上WorkA到C将由
ChildThread()
(因为如果WorkA到C是在主线程以外的线程上执行的,则存在软件限制)我想要一种方法,以便在问题发生后,
ChildThread()
可以获得主线程中运行情况的某种指示。谢谢,但是由于程序的限制,
WorkB
不能在另一个线程上(Unity)。如果
WorkB
确实通过
Task WorkB=WorkB();
成为了一项任务,那就意味着我们已经把它放在了另一个线程中了?(因此我们可以等待它)@5.如果您使用的是Unity,那么您使用的是2017年的实验版本吗?否则,Unity不知道Task。我假设workb可以在不同的平台上运行thread@5argon一个操作是异步的这一事实并不意味着它正在使用另一个线程。在另一个线程中运行代码只是使操作异步的一种方法非同步的。@5argon不管现在有什么问题,我建议您等待,因为我发现Unity将来可能会允许UnityWebRequest在不同的线程上运行(否则,为什么还要允许不同的线程…?)斯蒂芬·克利里的答案正是你想要的。哦,我刚在年读到关于随意手动创建你自己的
任务
,意识到这实际上是斯蒂芬·克利里的答案。我想现在没事了。(有了这个,实际上这个答案几乎等于Stephen的答案,通过使
WorkB
的内部产生
TaskCompletionSource
->
Task
)谢谢,但是
WorkB
由于程序的限制不能在另一个线程上(Unity)。如果
WorkB
确实通过
Task WorkB=WorkB();
成为了一项任务,那就意味着我们已经把它放在了另一个线程中了?(因此我们可以等待它)@5.如果您使用的是Unity,那么您使用的是2017年的实验版本吗?否则,Unity不知道Task。我假设workb可以在不同的平台上运行thread@5argon一个操作是异步的这一事实并不意味着它正在使用另一个线程。在另一个线程中运行代码只是使操作异步的一种方法非同步的。@5argon不管现在有什么问题,我建议您等待,因为我发现Unity将来可能会允许UnityWebRequest在不同的线程上运行(否则,为什么还要允许