如何在C ++中设计高效的图像缓冲区?

时间:2009-10-21 04:24:13

标签: c++ image boost buffer shared-ptr

我正在尝试创建一个数据缓冲区,更具体地说,是一个图像缓冲区,它将在多个模块之间共享。这些模块只从缓冲区读取,根本不相互通信。我的困难是:

1.大数据量:

  

每张图像大于10M,这意味着不希望为不同的线程复制这些数据

2.我不希望记忆变得狂野:

  

当新数据不断进入(实时)时,必须在所有模块完成使用后删除非常旧的数据。

     

然而,为了使事情变得更复杂,那些消耗数据的模块处于不同的速度:一些更快/更慢,一些需要更多数据(多个图像)来获得结果,一些需要更少(仅一个图像)

我一直在考虑使用shared_ptr来解决第一个问题:创建一个boost shared_ptr(s)队列,每个shared_ptr()都指向一个图像(char数组)。然后将这些指针的子集传递给不同的模块。

我是这个智能指针领域的新手。什么是这个问题的好方法?

感谢。

6 个答案:

答案 0 :(得分:3)

Boost共享指针正是我要建议的。是的,让指针类为你工作。

请注意,如果要存储数组指针,则需要使用boost::shared_array而不是shared_ptr。

  

shared_array类模板存储指向动态分配的数组的指针。 (动态分配的数组使用C ++ new[]表达式进行分配。)指向的对象保证在指向它的最后一个shared_array被销毁或重置时被删除。

答案 1 :(得分:2)

假设您在创建缓冲区后立即将shared_ptr传递给模块,它们非常适合。在这种情况下,您甚至不需要集中存储它们。

然而,它变得更加复杂,如果你在一个点上创建缓冲区,而在某个其他点之后,模块会请求缓冲区。
在这种情况下,你必须弄清楚你想要的行为 你想把缓冲区保留一段时间吗?或者直到至少有一个模块使用它们?或者直到有一些新数据出现?

评论整合:
由于您希望所有读取器/模块都能处理所有传入数据,因此您可以简单地为这些输入队列提供输入。在传入数据时,只需将模块shared_ptr / shared_array传递给新缓冲区,然后将其添加到队列中。
请记住处理队列访问的多线程问题。

答案 2 :(得分:1)

根据您的要求,我认为您可以使用两个原则:

  • shared_array<char>将处理多线程同步和内存处理
  • 每个模块一个队列:这个是必需的,因为每个模块都按照自己的节奏处理图像

然后,只要获得图像,就可以在shared_array<char>的堆上分配它。然后在所有队列中复制该指针。

每个队列都需要同步,但它是一个经典的消费者/生产者的东西,所以你可能很容易编程(非常),特别是因为每个队列只有一个生产者(接收图像的线程)和一个消费者。

让我们举一个例子:让我们看3个模块,一个是快速的,一个是中等的,最后一个使用3×3的图像。

=> receiving image 1
module a: ['1'] -> processing (none)
module b: ['1'] -> processing (none)
module c: ['1'] -> processing (none)

=> modules a, b starts treatment of '1'
module a: [] -> processing '1'
module b: [] -> processing '1'
module c: ['1'] -> processing (none)

=> receiving image 2
module a: ['2'] -> processing '1'
module b: ['2'] -> processing '1'
module c: ['2', '1'] -> processing (none)

=> module a finishes treatment of '1', starts treatment of '2'
module a: [] -> processing '2'
module b: ['2'] -> processing '1'
module c: ['2', '1'] -> processing (none)

=> receiving image 3
module a: ['3'] -> processing '2'
module b: ['3', '2'] -> processing '1'
module c: ['3', '2', '1'] -> processing (none)

=> module c starts treatment of '1', '2' and '3'
module a: ['3'] -> processing '2'
module b: ['3', '2'] -> processing '1'
module c: [] -> processing '1', '2' and '3'

=> module a finishes treatment of '2', starts treatment of '3'
=> module b finishes treatment of '1', starts treatment of '2'
=> module c finishes treatment of '1' and '2', keeps '3' for future batch
module a: [] -> processing '3'
module b: ['3'] -> processing '2'
module c: [] -> processing '3' (waiting)

--> at this point '1' is deleted from memory

如果每个模块(线程)在“池”中注册其队列,您甚至可以使这个“简单”。

我还建议发信号,我一直认为生产者发信号通知新项目已插入(如果队列为空)更好,让消费者线程不断轮询队列......

答案 3 :(得分:0)

  

1.大数据量:

您选择将图像数据存储在堆分配的缓冲区中,然后在处理模块之间传递指针,这是正确的。

  

2.我不希望记忆变得狂野

如果使用shared_ptr(),则不必使用队列进行内存管理。设计模块以在需要访问数据时创建/接受shared_ptr(),并在完成后删除shared_ptr()。 shared_ptr()的意图是当没有对它的引用时删除指针所拥有的堆内存。

答案 4 :(得分:0)

将图像保存到文件中,这样您就可以尝试使用posix文件映射来映射到每个图像的内存。在映射之后,您可以将其作为共享内存,即使在多进程中也能有效使用。

顺便说一句:您的系统是否支持posix文件映射?例如Linux等中的mmap。

答案 5 :(得分:0)

使用boost::shared_array作为数据容器(John建议)。并boost::circular_buffer作为模块中的输入队列。

boost::circular_buffer< const boost::shared_array<char> > input_queue_;

在共享图像时,您不应修改它们,而是在需要时制作新副本。