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/

相关文章:

java - 我的代码线程不安全吗?

c# - 如何从客户端保护密码?是否需要或 HTTPS/SSL 就足够了?

java - CompletableFuture 包装器

c# - 如何将事件推送到 iPhone 日历

python - 在 Python 中线程多个 SQL 查询的良好实践/设计是什么

c# - 统一: Detect if the Return or Done key was pressed in the native iOS keyboard

c# - Unity3d 5 WavePro 动态网格碰撞器

c# - 如何为Android应用程序统一访问手机后退按钮

c# - 将结构从 C# 传递到 C++

c# - 如何在控制台应用程序中将文件移动到回收站?