2012-09-21 50 views
-1

我正在開發一個項目,我需要從文件中加載和處理千兆字節的序列。由於我處理大量數據,因此我無法將其保存在RAM上。所以我使用一個線程從這個文件加載數據並保存在一個隊列和一個線程中,一旦檢測到隊列中有東西,就將它卸載到某個臨時文件中。如何解決OpenMP內存訪問中的競爭條件?

我在做這個時遇到了一些麻煩。看起來有一個賽車狀況。有時會起作用,有時會返回分段錯誤。

我寫了一個最小的代碼示例與錯誤。

這是我隊列代碼

//#################### 
// STRUCTS 
//#################### 
struct queue_item{ 
    char *seq; 
    struct queue_item *prox;//Next element 
}; 
typedef struct queue_item QueueItem; 

struct Queue{ 
    QueueItem *first;//First element on queue 
    QueueItem *end;//Last element on queue 
    int size;//Queue size 
}; 
typedef struct Queue Queue; 

//#################### 

Queue* create_queue(){ 
    Queue *f; 
    f = (Queue*)malloc(sizeof(Queue)); 
    f->size = 0; 
    return f; 
} 

QueueItem* new_queue_item(char *seq){ 
    QueueItem* new; 
    int n; 

    n = strlen(seq); 
    new = (QueueItem*)malloc(sizeof(QueueItem)); 
    new->seq = (char*)malloc((n+1)*sizeof(char)); 

    strcpy(new->seq,seq); 

    return new; 
} 

void enqueue(Queue *f,char *seq){ 
    QueueItem* new; 
    new = new_queue_item(seq); 

    switch(f->size){ 
     case 0: 
      f->first = new; 
     break; 
     case 1: 
      f->end = new; 
      f->first->prox = f->end; 
     break; 
     default: 
      f->end->prox = new; 
      f->end = new; 
     break; 
    } 

    f->size = f->size + 1; 
    return; 
} 

char* dequeue(Queue *f){ 
    QueueItem *hold; 
    char *seq; 

    if(f->size > 0){ 
     hold = f->first; 
     seq = f->first->seq; 
     f->first = f->first->prox; 
     free(hold); 
     f->size--; 
    } 

    return seq; 
} 

int queue_size(Queue *f){ 
    return f->size; 
} 

void seq_to_file(char *seq,FILE *f){ 
    if(seq != NULL){ 
     fputs(seq,f); 
     free(seq); 
    } 
    return; 
} 

這是我的主要代碼

Queue *f; 
int i; 
int end_flag; 
char *seq; 

f = create_queue(); 
end_flag = 0; 

#pragma omp parallel shared(f) shared(end_flag) 
{ 
    #pragma omp sections 
    { 
     #pragma omp section 
     { 
      FILE *tmp; 
      tmp = fopen("tmp","w"); 
      while(!end_flag){ 
       if(queue_size(f) > 0) 
        seq_to_file(dequeue(f),tmp); 
      } 

      fclose(tmp);  
     } 
     #pragma omp section 
     { 
      seq = (char*)malloc(21*sizeof(char)); 
      strcpy(seq,"ABCDEFGHIJKLMNOPQRST"); 

      for(i=0;i < NSEQS;i++) 
       enqueue(f,seq); 
      end_flag = 1; 
     } 
    } 
}  

,我發現了一些錯誤:

1 - 上new_queue_item malloc的錯誤()line: new-> seq =(char *)malloc((n + 1)* sizeof(char));

* glibc的檢測* /家/佩德羅/升降梭箱/Programação/ C /隊列/ fila_teste:雙遊離或腐敗(下):0x00000000006f3bd0 * glibc的檢測 /家/佩德羅/收存箱/ Programação/ C /隊列/ fila_teste:malloc()函數:存儲器訛誤(快速):0x00000000006f3b70 *

2 - new_queu_item malloc的誤差()行: 新=(QueueItem *)malloc的(的sizeof(QueueItem)); 3 - seq_to_file()行上的免費錯誤: free(seq);

* glibc的檢測* /家/佩德羅/升降梭箱/Programação/ C /隊列/ fila_teste:雙遊離或腐敗(下):0x0000000000cdd3f0 *

用gdb檢查我有: (GDB )print * f $ 16 = {first = 0x0,end = 0x611180,size = 426}

這第三個錯誤讓我覺得這確實是一個競態條件情況。

我試圖用「end_flag」模擬一個信號量,但不認爲這是足夠的。另外,不要認爲「關鍵」和「原子」子句在這裏會有幫助,因爲它們只保護代碼區域而不是內存訪問。

任何想法如何解決這個問題?

+0

您需要確保一次只有一個線程可以訪問隊列。如果兩個嘗試同時出隊,如果同時嘗試入隊和出隊,隊列可能會被損壞。 –

回答

1

如果您不打算重用的代碼,你可以使用下列內容:

#pragma omp critical(queueLock)

該指令將作爲一個「命名」的互斥體,「queueLock」,在上面的例子。在你的情況下,你必須在enqueue,dequeue和queue_size函數中使用它,因爲它們都使用共享數據。

如果您打算重用此代碼,您應該瞭解OpenMP鎖(omp_lock_t)。