私は単純なネイティブMFCアプリケーションを作成していますが、シンプルな並列プログラム(Mandelbrotセットを描画)を実行するためにConcurrency名前空間を使用しています。プログラムはこれまでのところ非常に基本的なものであり、一方のボタンをクリックすると並行して描画され、もう一方のボタンは並行して描画されます。シリアル実行機能は非常に基本的で、正しい画像を描画します。しかし、並列実行機能と同様に、デバッグビルドを実行してプログラムを終了すると、出力はメモリリークがあることを示します。ここで parallel_for関数によってメモリリークが発生する(時々)
はコードです: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
});}
並列実行のためのコードは、それが並列にマンデルブロ画像の別の行を作成し、シリアル実行コードとは異なり、スレッドを確認するために、クリティカルセクションのロックを使用しています同じデバイスコンテキストハンドルで対戦しないでください。
ここで、メモリリークが報告された理由は、リリースビルドを実行してもメモリリークが報告されないためです。また、並列実行機能を複数回実行していると、実際に使用されているメモリが増えていないことに気付かず、誰もが疑問に思うように6GBのRAMがあります。 パフォーマンスが向上する限り、私のクアッドコアマシンは実際には、シリアル実行からの計算+描画速度の約4倍の増加を示します。 私は同様の質問がmsdnウェブサイトで尋ねてきましたが、これはVSのバグかもしれないので、あまり使われていません。とにかく、私は並列プログラマーの意見が欲しいです。
あなたは、想定される漏れがどこから来たのか絞り込むことを試みましたか? GDIコード(GDIリソースリークはメモリリークとして報告されることはほとんどありません)からではないでしょうから、すべてを削除して、IteratePointループだけを並列に呼び出すようにしてください。まだ漏れている場合は、何をしているのかを見てください(提供されているコードサンプルからはわかりません)。 –
@Leo実際には、私はparallel_for関数からすべてを削除しました。それは、parallel_for文(おそらく)を持つだけで、デバッグビルドの実行時にメモリリークが発生するようです。私はそれがコンパイラ、デバッガ、またはVS10のインストールの小さな欠陥かもしれないと思われるようになっています。私はまだいくつかの説明が欲しい。 – sj755
無関係なコードをすべて削除するには、質問を編集する必要があります。そうすれば、人々は何がうまくいかないのかを見ることができるようになります。また、それは間違って報告されているだけではないと確信していますか?メモリリークツールは偽陽性で有名です。どのツールがそれを報告しており、正確に何を報告していますか? –