从另一个线程填充的对象读取数据
语言:c# (wpf)
情况:我必须从文件加载 3D 网格,然后填充 Viewport3D。
我想要做什么:我想在BackgroundWorker中加载3D网格,这样应用程序在加载3D网格时不需要停止;这需要几秒钟。
问题:问题不在于如何使用BackgroundWorker。这是有据可查的。当我想要填充 Viewport3D 的 Model3DGroup(3D 对象组)时,问题就出现了。
从文件加载 3D 网格时,在后台工作程序中,我使用网格中每个对象的所有点和三角形索引填充自定义网格类。我将它们分别存储在 Point3DCollections 和 Int32Collections 中。
public class LFSMeshObject
{
public Point3D Center;
public int Radius;
public int NumPoints;
public int NumTris;
public Color ObjectColor { get; private set; }
public Point3DCollection Points { get; private set; }
public Int32Collection Tris { get; private set; }
当这个填充的对象被传递回 GUI 线程时,我可以很好地读取存储在该对象中的所有值和属性。我还可以读取 Point3Dcollections 和 Int32Collections,将其复制到 MeshGeometry3D 中,然后进入 Model3DGroup,但随后会出现线程所有者异常,因为后台填充对象的属性属于后台线程。
DiffuseMaterial mDMat;
MeshGeometry3D mGeom;
Debug.WriteLine("num objects in mesh : {0}", _trackMesh.NumObjects);
for (int a = 0; a < _trackMesh.NumObjects; a++)
{
mGeom = new MeshGeometry3D();
mGeom.Positions = _trackMesh.TrackMeshObjects[a].Points;
mGeom.TriangleIndices = _trackMesh.TrackMeshObjects[a].Tris;
mDMat = new DiffuseMaterial();
mDMat.Brush = new SolidColorBrush(_trackMesh.TrackMeshObjects[a].ObjectColor);
// thread owner exception
_mgTrack.Children.Add(new GeometryModel3D(mGeom, mDMat));
}
问题是我正在读取对象(Point3DCollection / Int32Collection)而不是从后台填充的对象中复制的普通值吗?
当您在线程之间共享数据时,是否必须在另一个线程中创建要使用的所有数据(在其他对象中,即 MeshGeometry / Modelgroup 中)的副本?我们是否可以不在后台填充一个对象,然后在填充完成后在另一个线程中“简单地使用它”?
The language : c# (wpf)
The situation : I have to load a 3D mesh from a file after which I populate a Viewport3D.
What do I want to do : I want to load the 3D mesh in a BackgroundWorker, so the application does not need to stall while loading the 3D mesh; this takes a few seconds.
The problem : The problem is NOT how to use BackgroundWorker. That's well documented. The problem arises when I want to populate the Viewport3D's Model3DGroup (3D object group).
When loading the 3D mesh from the file, in the background worker, I populate a custom mesh class with all the points and triangle indices of each object in the mesh. I store these in Point3DCollections and Int32Collections respectively.
public class LFSMeshObject
{
public Point3D Center;
public int Radius;
public int NumPoints;
public int NumTris;
public Color ObjectColor { get; private set; }
public Point3DCollection Points { get; private set; }
public Int32Collection Tris { get; private set; }
When this populated object is passed back to the GUI thread, I can read all values and properties stored in the object just fine. I can also read the Point3Dcollections and Int32Collections which I copy into MeshGeometry3D's which go into the Model3DGroup, but then get a thread owner exception, because the properties of the background populated object belong to the background thread.
DiffuseMaterial mDMat;
MeshGeometry3D mGeom;
Debug.WriteLine("num objects in mesh : {0}", _trackMesh.NumObjects);
for (int a = 0; a < _trackMesh.NumObjects; a++)
{
mGeom = new MeshGeometry3D();
mGeom.Positions = _trackMesh.TrackMeshObjects[a].Points;
mGeom.TriangleIndices = _trackMesh.TrackMeshObjects[a].Tris;
mDMat = new DiffuseMaterial();
mDMat.Brush = new SolidColorBrush(_trackMesh.TrackMeshObjects[a].ObjectColor);
// thread owner exception
_mgTrack.Children.Add(new GeometryModel3D(mGeom, mDMat));
}
Is the problem that I'm reading objects (Point3DCollection / Int32Collection) instead of plain values which would be copied, from the background-populated object?
Is it so that when you share data between threads, you have to create copies of all the data you want to use (in other object ie. MeshGeometry / Modelgroup) in the other thread? Can we not populate an object in the background and then 'simply use it' in another thread, after population is complete?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
一个简单而肮脏的尝试是将函数指针(委托回调)传递到您从 gui 线程启动的线程的上下文。当您想要将其读回到 gui 线程时,该委托实际上会返回您想要读取的任何内容。所以回调是在主线程上创建的。这应该有效。
An easy and dirty thing to try is to pass a function pointer (delegate callback) to the context of the thread you start up from the gui thread. That delegate will essentially return whatever that is that you want to read at exact moment when you want to read it back to the gui thread. So the callback is created on the main thread. This should work.
与此同时,我通过使用普通的 Point3D[] 和 int[] 数组而不是对应的 xxxCollection 数组解决了这个问题。然后,当我用这些数组填充 3D 模型时,它工作得很好。没有线程所有权错误。很奇怪......但显然有些对象(在后台线程上创建的)根本无法在另一个线程中访问,或者我错过了一些东西(可能 - 我只使用 c# 1.5 个月)。
In the meantime I've fixed the problem by using plain Point3D[] and int[] arrays instead of the xxxCollection counterparts. Then when I populate the 3D models with those arrays it works fine. No thread ownership errors. Weird ... but apparently some objects (that have been created on the background thread) can simply not be accessed in another thread, or I'm missing something (probably - I've only been using c# for 1.5 months).