2014-01-07 58 views
1

我使用OpenMP並行以下功能分段故障使用OpenMP

float myfunc (Class1 *class1, int *feas, int numfeas, float z, long *k, double cost, long iter, float e) 
{ 
    long i; 
    long x; 
    double sum; 

    sum = cost; 
    while (change/cost > 1.0*e) { 
     change = 0.0; 

     intshuffle (feas, numfeas); 

     #pragma omp parallel for private (i,x) firstprivate(z,k) reduction (+:sum) 
     for (i=0; i<iter; i++) { 
      x = i%numfeas; 
      sum += pgain (feas[x], class1, z, k); 
     } 
     cost -= sum; 
    } 
    return (cost); 
} 

這將返回一個「分割故障(核心轉儲)」錯誤

當我將編譯改變

#pragma omp parallel for private (i,x) firstprivate(class1,feas,z,k) reduction (+:sum)` 

我得到一個 「雙重釋放或腐敗(出):0xb6a00468」 E RROR。

從我有限的OpenMP的知識,我明白這是由於錯誤的內存訪問有關class1的FEAS指針。

僅供參考我還張貼我的Class1代碼

typedef struct { 
    float w; 
    float *c; 
    long a; 
    float co; 
} Class1; 

請諮詢到parallelise上述功能的正確方法。

更新:

的pgain功能

double pgain (long x, Class1 *class1, double z, long int *numcenters) 
{ 
    int i; 
    int number_of_centers_to_close = 0; 

    static double *work_mem; 
    static double gl_cost_of_opening_x; 
    static int gl_number_of_centers_to_close; 

    int stride = *numcenters + 2; 
    //make stride a multiple of CACHE_LINE 
    int cl = CACHE_LINE/sizeof (double); 
    if (stride % cl != 0) { 
     stride = cl * (stride/cl + 1); 
    } 
    int K = stride - 2 ; // K==*numcenters 

    //my own cost of opening x 
    double cost_of_opening_x = 0; 

    work_mem = (double*) malloc (2 * stride * sizeof (double)); 
    gl_cost_of_opening_x = 0; 
    gl_number_of_centers_to_close = 0; 

    /* 
    * For each center, we have a *lower* field that indicates 
    * how much we will save by closing the center. 
    */ 
    int count = 0; 
    for (int i = 0; i < class1->num; i++) { 
     if (is_center[i]) { 
      center_table[i] = count++; 
     } 
    } 
    work_mem[0] = 0; 

    //now we finish building the table. clear the working memory. 
    memset (switch_membership, 0, class1->num * sizeof (bool)); 
    memset (work_mem, 0, stride*sizeof (double)); 
    memset (work_mem+stride,0,stride*sizeof (double)); 

    //my *lower* fields 
    double* lower = &work_mem[0]; 
    //global *lower* fields 
    double* gl_lower = &work_mem[stride]; 

    #pragma omp parallel for 
    for (i = 0; i < class1->num; i++) { 
     float x_cost = dist (class1->p[i], class1->p[x], class1->dim) * class1->p[i].weight; 
     float current_cost = class1->p[i].cost; 

     if (x_cost < current_cost) { 

      // point i would save cost just by switching to x 
      // (note that i cannot be a median, 
      // or else dist(p[i], p[x]) would be 0) 

      switch_membership[i] = 1; 
      cost_of_opening_x += x_cost - current_cost; 

     } else { 

      // cost of assigning i to x is at least current assignment cost of i 

      // consider the savings that i's **current** median would realize 
      // if we reassigned that median and all its members to x; 
      // note we've already accounted for the fact that the median 
      // would save z by closing; now we have to subtract from the savings 
      // the extra cost of reassigning that median and its members 
      int assign = class1->p[i].assign; 
      lower[center_table[assign]] += current_cost - x_cost; 
     } 
    } 

    // at this time, we can calculate the cost of opening a center 
    // at x; if it is negative, we'll go through with opening it 

    for (int i = 0; i < class1->num; i++) { 
     if (is_center[i]) { 
      double low = z + work_mem[center_table[i]]; 
      gl_lower[center_table[i]] = low; 
      if (low > 0) { 
       // i is a median, and 
       // if we were to open x (which we still may not) we'd close i 

       // note, we'll ignore the following quantity unless we do open x 
       ++number_of_centers_to_close; 
       cost_of_opening_x -= low; 
      } 
     } 
    } 
    //use the rest of working memory to store the following 
    work_mem[K] = number_of_centers_to_close; 
    work_mem[K+1] = cost_of_opening_x; 

    gl_number_of_centers_to_close = (int) work_mem[K]; 
    gl_cost_of_opening_x = z + work_mem[K+1]; 

    // Now, check whether opening x would save cost; if so, do it, and 
    // otherwise do nothing 

    if (gl_cost_of_opening_x < 0) { 
     // we'd save money by opening x; we'll do it 
     #pragma omp parallel for 
     for (int i = 0; i < class1->num; i++) { 
      bool close_center = gl_lower[center_table[class1->p[i].assign]] > 0 ; 
      if (switch_membership[i] || close_center) { 
       // Either i's median (which may be i itself) is closing, 
       // or i is closer to x than to its current median 
       #pragma omp critical 
       { 
       class1->p[i].cost = class1->p[i].weight * dist (class1->p[i], class1->p[x], class1->dim); 
       class1->p[i].assign = x; 
       } 
      } 
     } 
     for (int i = 0; i < class1->num; i++) { 
      if (is_center[i] && gl_lower[center_table[i]] > 0) { 
       is_center[i] = false; 
      } 
     } 
     if (x >= 0 && x < class1->num) { 
      is_center[x] = true; 
     } 

     *numcenters = *numcenters + 1 - gl_number_of_centers_to_close; 
    } else { 
     gl_cost_of_opening_x = 0; // the value we'll return 
    } 

    free (work_mem); 

    return -gl_cost_of_opening_x; 
} 

更新2

在我的版本修正了pgain因爲我有#pragma指令也pgain

這裏是一個堆棧跟蹤

#0 0xb7d50750 in ??() from /lib/i386-linux-gnu/libc.so.6 
#1 0xb7eaa198 in ??() from /usr/lib/i386-linux-gnu/libgomp.so.1 
#2 0x080493a0 in pgain (x=2982, class1=0xbffff218, z=1461.919921875, 
    numce=0x804d128) at streamcluster-openmp.cpp:232 
#3 0x0804aaf6 in myfunc(Class1*, int*, int, float, long*, double, long, float) [clone ._omp_fn.0]() at openmp.cpp:347 
#4 0xb7ea9889 in ??() from /usr/lib/i386-linux-gnu/libgomp.so.1 
#5 0xb7cbcd4c in start_thread() from /lib/i386-linux-gnu/libpthread.so.0 
#6 0xb7dc9bae in clone() from /lib/i386-linux-gnu/libc.so.6 
+4

什麼是'pgain'? – Mysticial

+0

你確定'我'必須是私人的嗎?我敢肯定,你可以忽略該指令,並內聯'x'。我需要回顧一下我的OpenMP筆記... – millinon

+0

@Mysticial pgain是另一個函數,簽名是double pgain(long x,Class1 * class1,double z,long int * numcent)。但是它並不重要,因爲沒有OpenMP Pragma,代碼編譯和運行正確 –

回答

2

該問題可能是一個可能的競爭條件在pgain這一部分:

// Either i's median (which may be i itself) is closing, 
// or i is closer to x than to its current median 
class1->p[i].cost = class1->p[i].weight * dist (class1->p[i], class1->p[x], class1->dim); 
class1->p[i].assign = x; 

由於class1是一個指針,你自己創造私人用下面的語句firstprivate(class1)是裸指針,而不是基本的資源。

此問題的解決方案高度依賴於程序的語義。如果是罰款已隨機排序的*class1更新,資源被真正的意思共享,那麼以下修改:

// Either i's median (which may be i itself) is closing, 
// or i is closer to x than to its current median 
#pragma omp critical LOCK_CLASS1 
{ 
    // Lock this part of the code for thread-safety 
    class1->p[i].cost = class1->p[i].weight * dist (class1->p[i], class1->p[x], class1->dim); 
    class1->p[i].assign = x 
} 

將解決上面的代碼。否則,您應在致電pgain之前爲每個線程創建*class1的私人副本。

最後,您應該注意,上述推理仍然適用於任何資源。例如,Class1中的指針float *c在引用共享的資源並且不同步內存更新時顯示相同的臨界點。

+0

那麼,您對解決問題的建議解決方案是什麼? –

+0

@AlexanderTalavari查看更新 – Massimiliano

+0

無法修復它。我用新的信息更新了我原來的帖子。 –