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

发布于 2024-08-07 22:44:21 字数 500 浏览 5 评论 0原文

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

1.数据量大:

每个图像大于 10M,这意味着为不同线程复制这些数据是不可取的

2.我不希望内存变得疯狂:

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

但是,让事情变得更加复杂的是,那些消耗数据的模块的速度不同:有些更快/更慢,有些需要更多数据(多个图像)才能获得结果,有些需要更少数据(仅一张图像)

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

我是这个智能指针领域的新手。对于这个问题有什么好的解决方案吗?

谢谢。

I am trying to create a data buffer, more specifically, an image buffer, which will be shared among multiple modules. Those modules only reads from the buffer and don't communicate with each other at all. My difficulty is:

1.Large data size:

larger than 10M per image, that means copying those data around for different threads is not desirable

2.I don't want the memory grow wild:

as new data continuously come in(in real-time), the very old data must be deleted when all the modules have finished using it.

However, to make things even more complex, those modules who consumes the data are at different pace: some are faster/slower, some needs more data(multiple images) to get a result, some need less(only one image)

I have been thinking about using shared_ptr to solve the 1st problem: create a queue of boost shared_ptr(s), each shared_ptr() points to an image(char array). Then pass a subset of those pointers to different module.

I am a totally newbie in this smart pointer field. What will be a good solution for this problem?

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

随风而去 2024-08-14 22:44:21

Boost 共享指针正是我要建议的。是的,让指针类为您完成这项工作。

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

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

A Boost shared pointer is exactly what I was going to suggest. Yes, let the pointer class do the work for you.

Note that you will want to use boost::shared_array instead of shared_ptr if you are storing array pointers.

The shared_array class template stores a pointer to a dynamically allocated array. (Dynamically allocated array are allocated with the C++ new[] expression.) The object pointed to is guaranteed to be deleted when the last shared_array pointing to it is destroyed or reset.

沧桑㈠ 2024-08-14 22:44:21

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

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

评论整合:
当您希望所有读取器/模块处理所有传入数据时,您可以简单地为它们提供一个输入队列。在传入数据时,只需将 shared_ptr/shared_array 传递给模块到新缓冲区,该缓冲区会将它们添加到队列中。
记住要处理队列访问的多线程问题。

Assuming you hand the shared_ptrs to the modules as soon as the buffer is created, they are a good fit. You don't even need to store them centrally in that case.

It gets more complicated however, if you create the buffers at one point and only at some other point later the modules request the buffer.
In that case you have to figure out what behaviour you want.
Do you want to hold the buffers for some time? Or until at least one module has used them? Or until some new data comes in?

integration of comment:
As you want all your readers/modules to handle all incoming data you can simply give these an input queue. On incoming data just hand the modules an shared_ptr/shared_array to the new buffer, which add them to the queue.
Remember to handle the multi-threading issues though for the queue access.

粉红×色少女 2024-08-14 22:44:21

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

  • shared_array 它将处理多线程同步和内存处理
  • 每个模块一个队列:这个是必要的,因为每个模块都在处理 然后,一旦获得图像

,就将其分配到堆上的 shared_array 中。然后,该指针将被复制到所有队列中。

每个队列都单独需要同步,但这是一个经典的消费者/生产者事物,因此您可能会(相当)轻松地对其进行编程,特别是因为每个队列只有一个生产者(接收图像的线程)和一个消费者。

让我们举个例子:让我们采用 3 个模块,一个是快速的,一个是中等的,最后一个使用 3 x 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

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

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

According to your requirements, I think you could use two principles:

  • shared_array<char> which will handle the multi-thread synchronization and memory-handling
  • one queue per module: this one is necessary since each module is dealing with the images at its own pace

Then, as soon as you get an image, you allocate it on the heap in a shared_array<char>. This pointer is then replicated in all the queues.

Each queue individually requires synchronization, it's a classic Consumer / Producer thing though, so you'll probably program it (quite) easily, especially since each queue only have ONE producer (the thread which receives the image) and ONE consumer.

Let's have an example: let's take 3 modules, one is fast, one is medium and the last use the images 3 by 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

You can even make this 'easy' if each module (thread) registers its queue in a 'pool'.

I would also advise signalling, I always think it was better for a producer to signal that a new item had been inserted (if the queue was empty) that having the consumer thread constantly polling the queue...

拥抱我好吗 2024-08-14 22:44:21

1.大数据量:

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

2.我不想让记忆变得疯狂

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

1.Large data size:

You are correct in choosing to store the image data in heap allocated buffers, and then passing pointers to them between your processing modules.

2.I don't want the memory grow wild

You don't have to use a queue for memory management if you are using shared_ptr(). Design your modules to create/accept a shared_ptr() when it needs access to the data, and when it is done, to delete the shared_ptr(). The intention of a shared_ptr() is that the heap memory owned by the pointer is deleted when there are no more references to it.

妄想挽回 2024-08-14 22:44:21

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

顺便问一下:您的系统支持 posix 文件映射吗?例如 Linux 中的 mmap 等。

save the image to a file so you could try posix file mapping to map to memory per image. after mapping, you could make it as the shared memory to be used efficiently even among multi-processes.

Btw: does your system support posix file mapping? e.g. mmap in Linux etc.

红焚 2024-08-14 22:44:21

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

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

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

Use boost::shared_array as data container (John suggestion). And boost::circular_buffer as input queue in your modules.

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

As images are shared you should not modify them but make a new copy when needed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文