2012-02-11 7 views
2

Первоначально у меня был однопоточный цикл, который выполняет итерацию по всем пикселям изображения и может выполнять различные операции с данными.распределение памяти на поток в цикле parallel_for

Библиотека, которую я использую, диктует, что извлечение пикселей из изображения должно выполняться по одной строке за раз. С этой целью я malloc блок памяти, который может провести одну строку пикселей (BMM_Color_fl это структура, содержащая данные RGBA одного пикселя в виде четырех значений с плавающей точкой, и GetLinearPixels() копий одной строки пикселей из растрового изображения в BMM_Color_fl массиве.)

BMM_Color_fl* line = (BMM_Color_fl*)malloc(width * sizeof(BMM_Color_fl)); 
for (int y = 0; y < height, y++) 
{ 
    bmp->GetLinearPixels(0, y, width, line); //Copy data of row Y from bitmap into line. 
    BMM_Color_fl* pixel = line; //Get first pixel of line. 
    for (int x = 0; x < width; x++, pixel++) // For each pixel in the row... 
    { 
     //Do stuff with a pixel. 
    } 
} 
free(line); 

Пока все хорошо!

Ради сокращения времени выполнения этого цикла, я написал параллельную версию с помощью parallel_for, который выглядит следующим образом:

parallel_for(0, height, [&](int y) 
{ 
    BMM_Color_fl* line = (BMM_Color_fl*)malloc(width * sizeof(BMM_Color_fl)); 
    bmp->GetLinearPixels(0, y, width, line); 
    BMM_Color_fl* pixel = line; 
    for (int x = 0; x < width; x++, pixel++) 
    { 
     //Do stuff with a pixel. 
    } 
    free(line); 
}); 

Хотя многопоточный цикл уже быстрее, чем оригинал, я понимаю, это невозможно для всех потоков использовать один и тот же блок памяти, поэтому в настоящее время я выделяю и освобождаю память на каждой итерации цикла, что явно расточительно, поскольку никогда не будет больше потоков, чем итерации цикла.

Мой вопрос в том, есть ли и как я могу каждый поток malloc использовать только один буфер и использовать его повторно (и в идеале, бесплатно в конце)?

  • Как отказ от ответственности Я должен указать, что я новичок в C++.

Реализация предложенных решений:

Concurrency::combinable<std::vector<BMM_Color_fl>> line; 

parallel_for(0, height, [&] (int y) 
{ 
    std::vector<BMM_Color_fl> lineL = line.local(); 
    if (lineL.capacity() < width) lineL.reserve(width); 

    bmp->GetLinearPixels(0, y, width, &lineL[0]); 

    for (int x = 0; x < width; x++) 
    { 
     BMM_Color_fl* pixel = &lineL[x]; 
     //Do stuff with a pixel. 
    }  
}); 

Как было предложено, я консервирования malloc и заменил его vector + reserve.

+1

Извините, но я не могу * не жалуюсь: 'malloc' не имеет места в коде C++. Ни при каких обстоятельствах, если вы на самом деле не выполняете собственный распределитель в терминах 'malloc' (но почему бы вы никогда не делали этого, это выходит за рамки меня, поскольку он уже использует этот распределитель по умолчанию). –

+0

@ Konrad Я не спорю, но не могли бы вы объяснить, почему? – Rotem

+0

Поскольку C++ специально инкапсулирует механизм 'malloc' /' free' двумя способами: (1) через 'new' /' delete' и (2) через распределители. Оба обеспечивают превосходный интерфейс из-за сильной типизации. Это улучшает читаемость и позволяет избежать ошибок типа. Кроме того, даже эти методы должны в общем случае (читай: почти * всегда *) избегать в пользу управляемой памяти (в вашем случае, «std :: vector», но более общие умные указатели), чтобы избежать утечек памяти и упростить код (нет явной очистки). –

ответ

0

Для достижения этой цели вы можете использовать класс Concurrency::combinable. Я ленив, чтобы опубликовать код, но я уверен, что это возможно.

+0

Спасибо за указатель. Если я правильно вас понимаю, я должен создать 'combinable ' объект длины 'width' и вызывать его' .local() 'внутри цикла? И если да, то это будет создание копии массива на поток или на каждую итерацию цикла? – Rotem

+0

никогда не думал, понял. Добавлен код решения в конце вопроса. – Rotem

0

Вместо того, чтобы каждый вызов потока parallel_for() вызывал у них другую функцию, которая выделяет память, вызывает parallel_for(), а затем освобождает память.

+0

Я не уверен, что вы имеете в виду. Я не запускаю какие-либо потоки вручную, я вызываю parallel_for из моего основного потока, который автоматически разбивает итерации цикла на отдельные потоки. – Rotem

+0

Да, но, как вы сказали, вы делаете alloction внутри цикла for. Вы хотите поместить malloc/free вне цикла for. Вы можете сделать это, создав еще одну функцию, которая выполняет mallocs, вызывает parallel_for() и освобождает память. Затем назовите это для каждого потока. – salsaman

+0

Извините, я до сих пор не пойду. Вы предполагаете, что я создаю кучу новых потоков и каждый из них вызывает alloc/parallel_for/free? Разве это не приведет к тому, что каждый поток будет порождать больше потоков внутри parallel_for? И не будет ли это еще не работать, потому что каждый parallel_for будет ошибочно использовать один блок памяти для всех потоков? – Rotem