C# 在主线程关联中执行 Threading.ThreadPool.QueueUserWorkItem 回调

标签 c# multithreading unity3d

我想在 Unity 中从磁盘加载一堆图像。所以我想使用线程池在辅助线程中实际加载图像字节,然后在主线程中应用纹理。

我创建了一个函数,它获取一个路径作为输入并在 System.Threading.ThreadPool.QueueUserWorkItem 的帮助下加载图像字节,当它完成时它调用一个创建纹理的回调这些字节并将其应用于游戏对象。

我遇到的问题是回调是通过工作线程的关联执行的。 unity 不允许非主线程对其数据进行修改。

有没有办法在主线程的affinity中执行回调?

这是相关代码:

 public delegate void OnBytesLoaded(byte[] bytes);

    private void LoadBytesToTexture(byte[] bytes)
    {
        Texture2D texture = new Texture2D(100, 100);
        texture.LoadImage(bytes);
        thumbnail.texture = texture;
    }

    private void LoadTextureImage(string imagePath)
    {
        OnBytesLoaded callback = new OnBytesLoaded(LoadBytesToTexture);

        System.Threading.ThreadPool.QueueUserWorkItem(o =>
        {
            byte[] bytes = System.IO.File.ReadAllBytes(imagePath);
            Debug.Log($"Loaded image bytes");
            callback?.Invoke(bytes);
        });
    }

正如我所说,我的问题是 LoadBytesToTexture 在线程池线程而非主线程的关联中执行。

最佳答案

.NET 中有一个概念叫做 SynchronizationContext .

简而言之,同步上下文可以委托(delegate)工作给它有关联的线程(根据框架,这可以是线程池GUI 线程创建同步上下文的线程 ... 等等)。

使用这样的东西应该可以完成工作:

private void LoadTextureImage(string imagePath)
{
    var syncContext = SynchronizationContext.Current;
    OnBytesLoaded callback = new OnBytesLoaded(bytes => syncContext .Post(_ => LoadBytesToTexture(bytes), null));

    System.Threading.ThreadPool.QueueUserWorkItem(o =>
    {
        byte[] bytes = System.IO.File.ReadAllBytes(imagePath);
        Debug.Log($"Loaded image bytes");
        callback?.Invoke(bytes);
    });
}

注意:
SynchronizationContext 取决于调用上下文。

在当前场景中,syncContextbytes => syncContext.Post 的闭包中捕获,这样
.Current 属性将返回 syncContext 将工作委托(delegate)回 GUI 线程(因为 LoadTextureImage 是从 < strong>GUI线程),
否则,如果我们使用了 bytes => SynchronizationContext.Current.Post 这可能会产生 nullsyncContext 将工作委托(delegate)回 ThreadPool(因为 .Current 是从池中的线程调用的)。


要求从以下评论中获取更多信息:

OnBytesLoaded(bytes => syncContext .Post(_ => LoadBytesToTexture(bytes), null))

这个
OnBytesLoaded callback = new OnBytesLoaded(LoadBytesToTexture);

相同 OnBytesLoaded callback = new OnBytesLoaded(bytes => LoadBytesToTexture(bytes));

在代码的原始版本中,您使用 LoadBytesToTexture 作为 OnBytesLoaded 的委托(delegate)(它需要具有以下定义的方法/委托(delegate) byte[] -> void), 现在我们正在传递新的委托(delegate),它将使用 syncContextLoadBytesToTexture 排队返回到 GUI 线程,它再次具有相同的定义 bytes [] -> 作废。
我们不是直接调用 LoadBytesToTexture,而是告诉 syncContext 使用在此调用中传递的字节 callback?.Invoke(bytes)

关于C# 在主线程关联中执行 Threading.ThreadPool.QueueUserWorkItem 回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58363535/

相关文章:

c# - 使用不同的功能在数组按钮中分配不同的文本名称

C# node graph api 使用

c# - 在 System.ConsoleKey 值使用完毕后,如何使它无效(或分配另一个值)?

java - 在多线程中 : How to determine which thread stops first

c# - Unity3d 在构建后看不到项目文件夹中的 XML 文件

c# - 如果您使用和/或 (||/&&),.net 会停止检查 IF 语句的其余部分吗?

node.js - 在 NodeJS 中异步使用同步进程

使用 `pthread_create` 创建用户级线程或内核级线程?

c# - 无法在 Unity 项目上添加 EasyNetQ 的引用

c# - 自动填充检查器数组