2009-11-05 53 views
2

編輯:我可以毫無問題兩次運行同一程序,同時 - 我怎麼能複製這個使用OpenMP或一些其他的方法?OpenMP:導致堆腐敗,任何人?

這是問題的基本框架。

//Defined elsewhere 
class SomeClass 
{ 
public: 
    void Function() 
    { 
    // Allocate some memory 
    float *Data; 
    Data = new float[1024]; 

    // Declare a struct which will be used by functions defined in the DLL 
    SomeStruct Obj; 
    Obj = MemAllocFunctionInDLL(Obj); 

    // Call it 
    FunctionDefinedInDLL(Data,Obj); 

    // Clean up 
    MemDeallocFunctionInDLL(Obj); 
    delete [] Data;   
    } 
} 

void Bar() 
{ 
    #pragma omp parallel for 
    for(int j = 0;j<10;++j) 
    { 
    SomeClass X; 
    X.Function(); 
    } 
} 

我已經證實,當一些內存試圖通過MemDeallocFunctionInDLL()被釋放時,_CrtIsValidHeapPointer()斷言失敗。

這是因爲兩個線程都寫入相同的內存?

因此,要解決這個問題,我想我會做SomeClass私人(這是完全陌生的我,所以任何幫助表示讚賞)。

void Bar() 
{ 
    SomeClass X; 
    #pragma omp parallel for default(shared) private(X) 
    for(int j = 0;j<10;++j) 
    {   
    X.Function(); 
    } 
} 

而且現在當它試圖在一開始分配內存Data失敗。

注:如果需要,我可以改變的DLL

注:它運行完全沒有#pragma omp parallel for

編輯:現在Bar看起來是這樣的:

void Bar() 
{ 
    int j 
    #pragma omp parallel for default(none) private(j) 
    for(j = 0;j<10;++j) 
    { 
    SomeClass X;   
    X.Function(); 
    } 
} 

仍然沒有運氣。

+0

也許不相關,但用new []分配的內存應該用delete []刪除。 – 2009-11-05 17:00:17

+0

謝謝,知道了 - 並更新了。 – Jacob 2009-11-05 17:09:37

回答

5

退房MemAllocFunctionInDLL,FunctionDefinedInDLL,MemDeallocFunctionInDLL是線程安全,或重入。換句話說,做這些函數是靜態變量還是共享變量?在這種情況下,你需要確保這些變量不被其他線程破壞。

沒有omp-for的事實很好,可能意味着你沒有正確地編寫一些函數來保證線程安全。

我想看看Mem(Alloc | Dealloc)FunctionInDLL中使用了什麼樣的內存分配/自由函數。

加入:我很確定你在DLL中的函數不是線程安全的。你可以同時運行這個程序沒有問題。是的,除非您的程序使用全系統共享資源(例如全局內存或進程間的共享內存),否則它應該沒問題,這非常少見。在這種情況下,線程中沒有共享變量,所以你的程序工作正常。

但是,在mutithreads調用這些功能(這意味着在單個進程)崩潰程序。這意味着線程之間有一些共享變量,並且可能已被破壞。

這不是OpenMP的問題,而只是一個多線程錯誤。解決這個問題可能很簡單。請看看DLL函數是否可以安全地被多線程併發調用。

如何私有化靜態變量

說,我們有這樣的全局變量:

static int g_data; 
static int* g_vector = new int[100]; 

私有化只不過是一個創造私人複製爲每個線程。

int g_data[num_threads]; 
int* g_vector[num_threads]; 
for (int i = 0; i < num_threads; ++i) 
    g_vector[i] = new int[100]; 

而且,當時這樣的變量,任何引用

// Thread: tid 
g_data[tid] = ... 
.. = g_vector[tid][..] 

是的,這是很簡單的。但是,這類代碼可能有false sharing問題。但是,虛假分享是一個表現問題,而不是正確性問題。

首先,試着將任何靜態和全局變量私有化。然後,檢查它的正確性。接下來,看看你會得到的加速。如果加速比是可擴展的(比方說四核心的速度快3.7倍),那就沒問題。但是,如果速度較低(例如四核上的2x加速),那麼您可能會看到虛假共享問題。爲了解決虛假共享問題,您只需在數據結構中添加一些填充即可。

+0

可能的即時變通辦法(並且它很愚蠢!)會在SomeClass :: Function中打開一個DLL實例。 而且,DLL中的分配/釋放只是malloc/free? – minjang 2009-11-05 19:26:05

+0

@Minjang:你說得對:我在代碼中發現了一大堆'static'變量。所以,我正在考慮重寫它並使其線程安全或重寫'Bar'來分離運行DLL函數的兩個進程。 – Jacob 2009-11-05 19:52:36

+0

很高興聽到:)在這種情況下,您需要對靜態變量進行「私有化」。如果DLL代碼編寫得很整潔,它可能非常簡單。如果這很難,那麼,正如你所說,分叉多個進程將是一種解決方法。 – minjang 2009-11-05 20:09:38

2

而不是

delete Data 

你必須寫

delete [] Data; 

無論你新的[],請務必使用delete []。

它看起來像你的問題不是特定於openmp。您是否嘗試在不包含#pragma parallel的情況下運行您的應用程序?

+0

是真實的,但這不會讓它崩潰,只是刪除第一個浮出的1023泄漏。 – gbjbaanb 2009-11-05 17:04:42

+1

我想你不能確定未定義行爲的影響。 – alexkr 2009-11-05 17:07:26

+0

是的,它運行完美,沒有'#pragma omp parallel for' – Jacob 2009-11-05 17:07:29

2

默認(共享)意味着所有變量在線程之間共享,這不是你想要的。將其更改爲默認值(無)。

私人(X)將X的副本,爲每個線程,但是,沒有人會被初始化,所以任何建築不一定會進行。

我想你會更好地與您最初的方法,把一個斷點在的dealloc來電,看看內存指針,它包含了什麼。您可以看到guard bytes以確定內存在單次調用結束時還是在線程後被覆蓋。

順便說一句,我假設這個工程,如果你運行一次,沒有omp循環?

+0

是的,它沒有omp編譯指示。 – Jacob 2009-11-05 18:19:10