gpt4 book ai didi

c# - 我怎样才能有两个独立的任务调度程序?

转载 作者:行者123 更新时间:2023-11-30 16:52:17 24 4
gpt4 key购买 nike

我正在编写一个游戏,并且使用 OpenGL 我需要将一些工作卸载到 OpenGL 上下文处于事件状态的渲染线程,但其他一切都由普通线程池处理。

有没有一种方法可以强制任务在一个特殊的线程池中执行,并且从 async 创建的任何新任务也被分派(dispatch)到该线程池?

我想要一些专门的渲染线程,并且我希望能够使用 asyncawait 来创建和填充顶点缓冲区。

如果我只使用自定义任务调度程序和 new Factory(new MyScheduler()) 似乎任何后续 Task 对象都会被分派(dispatch)到线程池Task.Factory.Scheduler 突然变为 null

以下代码应该显示我希望能够做什么:

public async Task Initialize()
{
// The two following tasks should run on the rendering thread pool
// They cannot run synchronously because that will cause them to fail.
this.VertexBuffer = await CreateVertexBuffer();
this.IndexBuffer = await CreateIndexBuffer();

// This should be dispatched, or run synchrounousyly, on the normal thread pool
Vertex[] vertices = CreateVertices();
// Issue task for filling vertex buffer on rendering thread pool
var fillVertexBufferTask = FillVertexBufffer(vertices, this.VertexBuffer);

// This should be dispatched, or run synchrounousyly, on the normal thread pool
short[] indices = CreateIndices();

// Wait for tasks on the rendering thread pool to complete.
await FillIndexBuffer(indices, this.IndexBuffer);
await fillVertexBufferTask; // Wait for the rendering task to complete.
}

有什么办法可以实现吗,还是超出了async/await的范围?

最佳答案

这是可能的,并且基本上与 Microsoft 为 Windows 窗体和 WPF 同步上下文所做的相同。

第一部分 - 您在 OpenGL 线程中,并且想要将一些工作放入线程池中,并且在完成此工作之后您想要返回到 OpenGL 线程中。

我认为您最好的解决方法是实现您自己的 SynchronizationContext .这个东西基本上控制 TaskScheduler 的工作方式以及它如何安排任务。默认实现只是将任务发送到线程池。您需要做的是将任务发送到专用线程(保存 OpenGL 上下文)并在那里一个一个地执行它们。

实现的关键是重写PostSend方法。两种方法都应执行回调,其中 Send 必须等待调用完成,而 Post 则不需要。使用线程池的示例实现是Send直接调用回调,Post将回调委托(delegate)给线程池。

对于您的 OpenGL 线程的执行队列,我认为是一个查询 BlockingCollection 的线程应该做得很好。只需将回调发送到此队列即可。您可能还需要一些回调,以防从错误的线程调用您的 post 方法并且您需要等待任务完成。

但总而言之,这种方式应该可行。例如,async/await 确保 SynchronizationContext 在线程池中执行异步调用后恢复。因此,在将一些工作转移到另一个线程后,您应该能够返回到 OpenGL 线程。

第二部分 - 您在另一个线程中并且想要将一些工作发送到 OpenGL 线程并等待该工作完成。

这也是可能的。在这种情况下,我的想法是您不使用 Task,而是使用其他 awaitable 对象。一般来说,每个对象都可以等待。它只需要实现一个公共(public)方法 getAwaiter(),该方法返回一个实现了 INotifyCompletion 的对象。界面。 await 所做的是将剩余的方法放入一个新的 Action 并将此操作发送到 OnCompleted该接口(interface)的方法。一旦等待的操作完成,等待者将调用计划的操作。此等待者还必须确保捕获 SynchronizationContext 并在捕获的 SynchronizationContext 上执行延续。这听起来很复杂,但是一旦你掌握了它,它就会变得相当容易。对我帮助很大的是 YieldAwaiter 的引用来源(这基本上就是使用 await Task.Yield() 时发生的情况)。这不是您需要的,但我认为这是一个起点。

返回等待者的方法必须负责将实际工作发送到必须执行它的线程(您可能已经有了第一部分的执行队列)并且等待者必须在工作完成后触发.

结论

别搞错了。这是很多工作。但是,如果你做了所有这些,你将会遇到更少的问题,因为你可以无缝地使用 async/await 模式,就像你在 Windows 窗体或 WPF 中工作一样那是色调加号。

关于c# - 我怎样才能有两个独立的任务调度程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32741375/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com