C# 我应该如何加载一个图像并在多线程C应用程序中传递它?

C# 我应该如何加载一个图像并在多线程C应用程序中传递它?,c#,thread-safety,C#,Thread Safety,我正在编写一个应用程序,其目的是在文件夹中查找图像,并将其呈现给用户,询问如何裁剪图像。由于我每天都在不同的语言之间跳跃,我倾向于把我的最佳实践和概念搞得一团糟,就是这样 程序流程是这样的:您将看到主窗体,带有一个浏览按钮,您也可以将文件夹放到其中。当您选择一个文件夹时,它会打开另一个表单,扫描所选文件夹中的.jp[e]g和.tif[f]图像,并将它们显示在列表中,询问您要裁剪其中的哪一个,以及一些其他选项。然后它返回到主窗体,该窗体遍历该窗体中选定图像的列表,并在BackgroundWorke

我正在编写一个应用程序,其目的是在文件夹中查找图像,并将其呈现给用户,询问如何裁剪图像。由于我每天都在不同的语言之间跳跃,我倾向于把我的最佳实践和概念搞得一团糟,就是这样

程序流程是这样的:您将看到主窗体,带有一个浏览按钮,您也可以将文件夹放到其中。当您选择一个文件夹时,它会打开另一个表单,扫描所选文件夹中的.jp[e]g和.tif[f]图像,并将它们显示在列表中,询问您要裁剪其中的哪一个,以及一些其他选项。然后它返回到主窗体,该窗体遍历该窗体中选定图像的列表,并在BackgroundWorker中为每个图像加载到裁剪窗体中,然后对其进行裁剪并保存

对于原型设计,我处理图像的加载有点混乱;它加载选择窗体文件夹中的所有图像,然后在裁剪器中逐个加载每个选定图像,然后在要裁剪和保存的主窗体中再加载一次。对于大型图像,这可能会使任务耗时,因为在最坏的情况下,此应用程序将处理高达4000px2的TIFF源图像


我想有一种方法可以只将每个位图加载一次到某种全局数组中,但对于应用程序来说,这将是VisualBasic或VB。因为我使用的是BackgroundWorker,所以我还必须担心线程安全,以及C是否会因为试图以不安全的方式访问某些内容而对我大喊大叫。关于如何在限制单个图像加载到位图对象的次数的同时实现应用程序的目的,有什么想法吗?

您有两个选择:一个比另一个更面向对象,但更难实现:

创建一些类,例如Document、BitmapDocument,或任何包含列表的类,在其中添加所有图像。不要担心多线程,只要在每次添加图像时锁定列表即可。根据您对位图所做的操作,您可能还需要锁定它们。锁定在c中并不难,例如locksomeVariable{…}复制已经加载到列表中的位图,因为不同的控件使用它们,不需要太多的内存/时间,因为这些都是RAM操作。当主应用程序必须将此文档类传递给所有子控件和窗体时,就会出现复杂情况。一旦每个控件都知道文档实例,对它的任何添加都将立即可用

B创建一些类,其中列表标记为internal和static,这样项目中的任何类都可以查看和使用它。这样,您使用的是一种全局数组,但不是完全全局的。由于内部标记的缘故,它仅在项目内部可见,并且仍然保存在类中。请注意,您仍然需要使用C的锁定机制来确保所有内容都是线程安全的

注意,不直接访问类成员,可以考虑编写方法来操作它们并适当锁定对象。这将是正确的编程实践。对于B,只需创建标记为internal和static的方法

我个人会更快地使用B muck来实现和调试,尤其是在原型设计中,因为使用B muck可以使将来转到A并不太困难

此外,如果使用B的内部静态对象和函数方法,您可以编写一些函数,如GetBitmapstring path,它可以从磁盘加载图像,还可以保存所有最近加载的图像的缓冲区,这样线程就不必从磁盘加载两次。

因为根据位图类实例成员不能保证线程安全,我看到了两个选项:

表现不错,但有点冒险 将所有内容作为位图对象加载,并将所有这些位图对象添加到。。。访问是线程安全的,而且速度非常快,因为实现基本上是无锁的

性能稍差,但风险不大 将所有文件加载为一个文件。当你需要位图时,你只需创建一个MemoryMappedFile,它将使用你之前创建的位图已经占用的相同内存,因此速度非常快,并让位图从那里加载其内容。。。当你的应用程序关闭或者你想清理的时候,你只需浏览字典并清除那些MemoryMappedFile对象


我将记住这些方法,以便在我编写的任何非线程化的东西中像这样传递对象。。。正如Yahia在下面所说的,实例化位图不能保证线程安全,我发现ListT也不能保证线程安全。