C++ C+中的多线程图像处理+;

C++ C+中的多线程图像处理+;,c++,multithreading,optimization,image-processing,parallel-processing,C++,Multithreading,Optimization,Image Processing,Parallel Processing,我正在做一个程序,它可以处理不同大小的图像。其中许多操作从输入读取像素数据并写入单独的输出(例如模糊)。这是在每像素的基础上完成的 这样的图像映射对CPU来说压力很大。我想使用多线程来加快速度。我该怎么做?我在考虑每行像素创建一个线程 我有几个要求: 可执行文件的大小必须最小化。换句话说,我不能使用大量的库。C/C++最轻量、可移植的线程库是什么 可执行文件的大小必须最小化。我想用一个函数forEachRow(fp*)为每一行运行一个线程,甚至是一个forEachPixel(fp*),其中fp

我正在做一个程序,它可以处理不同大小的图像。其中许多操作从输入读取像素数据并写入单独的输出(例如模糊)。这是在每像素的基础上完成的

这样的图像映射对CPU来说压力很大。我想使用多线程来加快速度。我该怎么做?我在考虑每行像素创建一个线程

我有几个要求:

  • 可执行文件的大小必须最小化。换句话说,我不能使用大量的库。C/C++最轻量、可移植的线程库是什么
  • 可执行文件的大小必须最小化。我想用一个函数forEachRow(fp*)为每一行运行一个线程,甚至是一个forEachPixel(fp*),其中fp在它自己的线程中对单个像素进行操作。哪一个最好?
    • 我应该使用正规函数、函子、函数体、lambda函数还是。。。还有别的吗
    • 某些操作使用优化,需要来自先前处理的像素的信息。这使得forEachRow很有利。即使考虑到这一点,使用forEachPixel会更好吗
  • 是否需要锁定只读和只读数组?
    • 仅从读取输入,但许多操作需要从阵列中的多个像素输入
    • 输出每像素仅写入一次
  • 当然,速度也很重要,但优化可执行文件大小优先
谢谢


关于这个主题的更多信息供好奇者参考:

我推荐
boost::thread
boost::gil
(通用图像库)。因为涉及到很多模板,我不确定代码大小是否仍然适合您。但是它是boost的一部分,所以可能值得一看。

我认为您不希望每行有一个线程。可能会有很多行,您将花费大量内存/CPU资源来启动/销毁线程,让CPU从一个线程切换到另一个线程。此外,如果您有使用C内核的P处理器,那么使用C*P线程可能不会有太多的收益

我建议您使用定义数量的客户端线程,例如N个线程,并使用应用程序的主线程将行分配给每个线程,或者它们可以简单地从“作业队列”获取指令。当一个线程处理完一行后,它可以在这个队列中签入另一行


至于库,您可以使用boost::thread,它非常轻便,也不太重。

每像素行一个线程是疯狂的,最好有大约n-1到2n个线程(对于n个cpu),并使每个循环获取一个作业单元(可能是一行或其他类型的分区)


在类似unix的平台上,使用pthreads,它简单且轻量级。

我可以问一下您是为哪个平台编写的吗?我猜这是因为可执行文件的大小是一个问题,而不是桌面计算机上的目标。在哪种情况下,平台具有多核或超线程?如果没有,那么在应用程序中添加线程可能会产生相反的效果,并使其速度减慢…

这是一种左撇子的想法

你在什么系统上运行这个?你想过在你的电脑上使用GPU吗


Nvidia有这方面的API

也许可以编写自己的微型库,为每个平台使用
\ifdef
实现一些标准线程功能?实际上没有太多,这将比您可以使用的任何库更大程度地减少可执行文件的大小

更新:对于工作分配-将您的图像分割成若干部分,并为每个线程分配一部分。这样,当这件作品完成时,它就完成了。通过这种方式,您可以避免实现会进一步增加可执行文件大小的作业队列。

如果您的编译器支持(我知道,gcc也支持),那么这样做会更容易

你不只是想制造大量的线程——当你开始获得越来越多的上下文切换时,增加新线程会降低回报。在某些情况下,使用太多线程实际上会使并行版本比仅使用线性算法更慢。线程的最佳数量是可用CPU/内核数量的函数,以及每个线程在I/O之类的事情上花费阻塞时间的百分比。请看Herb Sutter关于并行性能提高的一些讨论

OpenMP允许您轻松地根据可用CPU的数量调整创建的线程数量。使用它(特别是在数据处理案例中)通常只需要在现有代码中加入一些
#pragma omp
,并让编译器处理创建线程和同步

一般来说,只要数据不变,就不必锁定只读数据。如果可以确保每个像素槽只写入一次,并且可以保证在开始读取结果之前,所有写入操作都已完成,则也不必锁定

对于OpenMP,不需要对函子/函数对象执行任何特殊操作。以你认为最有意义的方式写下来。以下是来自(将rgb转换为灰度)的图像处理示例:

#pragma omp parallel for
对于(i=0;i

这会自动拆分为CPU数量相同的线程,并将阵列的一部分分配给每个线程。

还有另一个使用汇编进行优化的选项。现在,一个激动人心的动态代码生成项目是(它可以追溯到很久以前,是原始项目的站点)。它由尼克·卡彭斯(Nick Capens)开发,并发展成为现在的commerci
#pragma omp parallel for
for (i=0; i < numPixels; i++)
{
   pGrayScaleBitmap[i] = (unsigned BYTE)
       (pRGBBitmap[i].red * 0.299 +
        pRGBBitmap[i].green * 0.587 +
        pRGBBitmap[i].blue * 0.114);
}
* pthread_create, pthread_detach.
* pthread_mutexattr_init, pthread_mutexattr_settype, pthread_mutex_init,
* pthread_mutexattr_destroy, pthread_mutex_destroy, pthread_mutex_lock,
* pthread_mutex_trylock, pthread_mutex_unlock, pthread_mutex_timedlock.
* sem_init, sem_destroy, sem_post, sem_wait, sem_trywait, sem_timedwait.
/*ThreadA:*/ while(1){  mutex.lock();  printf("a\n");  usleep(100000); mutex.unlock(); }
/*ThreadB:*/ while(1){  mutex.lock();  printf("b\n");  usleep(100000); mutex.unlock(); }
#pragma omp parallel for 
for (i=0; i < numPixels; i++) 
{ ...} 
parallel_for(0,numPixels,1,ToGrayScale());
parallel_for(0,numPixels,1,[&](int i)
{  
   pGrayScaleBitmap[i] = (unsigned BYTE)  
       (pRGBBitmap[i].red * 0.299 +  
        pRGBBitmap[i].green * 0.587 +  
        pRGBBitmap[i].blue * 0.114);  
});