Функция parallel_for вызывает утечки памяти (иногда) - PullRequest
1 голос
/ 01 января 2011

Я делаю простое нативное приложение MFC и использую пространство имен Concurrency для выполнения простой параллельной программы (рисования набора Мандельброта). Программа пока что очень простая, нажатие одной кнопки рисует параллельно, другая - последовательно. Функция последовательного выполнения очень проста и рисует правильную картину. Как и функция параллельного выполнения, однако при запуске отладочной сборки и выходе из программы вывод сообщает, что произошла утечка памяти.

Вот код:

void CMandelbrotView::DrawSetParallel() {
// Get client area dimension which will be the image size
RECT rect;
GetClientRect(&rect);
//GetClientRect(pDC, &rect);
int imageHeight(rect.bottom);
int imageWidth(rect.right);

const double realMin(-2.1);             // Minimum real value
double imaginaryMin(-1.3);              // Minimum imaginary value
double imaginaryMax(+1.3);              // Maximum imaginary value
// Set maximum imaginary so axes are the same scale
double realMax(realMin+(imaginaryMax-imaginaryMin)*imageWidth/imageHeight);

// Get scale factors to convert pixel coordinates
double realScale((realMax-realMin)/(imageWidth-1));
double imaginaryScale((imaginaryMax-imaginaryMin)/(imageHeight-1));

CClientDC hdc(this);        // DC is for this view
OnPrepareDC(&hdc);          // Get origin adjusted

critical_section cs;            // Mutex for BitBlt() operation
parallel_for(0, imageHeight, [&](int y)         // Iterate parallel over image rows
{
    cs.lock();                                  // Lock for access to client DC
    // Create bitmap for one row of pixels in image
    HDC memDC = CreateCompatibleDC(hdc);        // Get device context to draw pixels
    HBITMAP bmp = CreateCompatibleBitmap(hdc, imageWidth, 1);
    cs.unlock();                                // We are done with hdc here so unlock
    HGDIOBJ oldBmp = SelectObject(memDC, bmp);  // Select bitmap into DC

    double cReal(0.0), cImaginary(0.0);     // Stores c components
    double zReal(0.0), zImaginary(0.0);     // Stores z components

    zImaginary = cImaginary = imaginaryMax - y*imaginaryScale;
    for(int x = 0; x < imageWidth; x++)     // Iterate over pixels in a row
    {
        zReal = cReal = realMin + x*realScale;
        // Set current pixel color based on n
        SetPixel(memDC, x, 0, Color(IteratePoint(zReal, zImaginary, cReal, cImaginary)));
    }

    cs.lock();                              // Lock to write to hdc
    // Transfer pixel row to client area device context
    BitBlt(hdc, 0, y, imageWidth, 1, memDC, 0, 0, SRCCOPY);
    cs.unlock();                            // Release the lock

    SelectObject(memDC, oldBmp);
    DeleteObject(bmp);                      // Delete bmp
    DeleteDC(memDC);                        // and our working DC
});}

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

Теперь я сказал, что иногда сообщается об утечке памяти, потому что запуск релизной сборки не приводит к утечке памяти. Кроме того, при многократном запуске функции параллельного выполнения я не замечаю, что используется больше памяти, у меня 6 ГБ ОЗУ на случай, если кому-то интересно. Что касается производительности, моя четырехъядерная машина на самом деле показывает примерно 4-кратное увеличение вычислений + скорость прорисовки при последовательном выполнении. Я также видел похожие вопросы на веб-сайте msdn, но они не очень полезны, потому что это может быть ошибка VS. В любом случае, я бы хотел мнение параллельного программиста.

Ответы [ 3 ]

1 голос
/ 01 января 2011

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

1 голос
/ 13 января 2011

Эта проблема описана в fix-list для VS2010 SP1. Статья обратной связи здесь . Помните, что SP1 все еще находится в бета-версии, поэтому не устанавливайте его на важные производственные машины. Скачать можно здесь .

0 голосов
/ 01 января 2011

Вы упомянули, что утечка происходит «несколько раз» и не всегда. Однако в вашем коде нет разветвлений (в частности, разветвлений с выделением памяти), поэтому оно должно всегда вызывать утечку или никогда не вызывать утечку. Более того, как уже упоминалось в моем комментарии, память выделяется только в двух местах для memDc and bmp, и вы правильно очищаете ресурсы для обеих переменных.

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

...