如何解决OpenMP内存访问中的竞争条件?

时间:2012-09-21 21:23:03

标签: c openmp race-condition

我正在开发一个项目,我需要从文件中加载和处理千兆字节的序列。由于我处理大量数据,我无法将其保存在RAM上。所以我使用一个线程从这个文件加载数据并保存在一个队列和一个线程中,一旦检测到队列中有东西,就把它卸载到一些临时文件中。

我在做这件事时遇到了一些麻烦。看起来有一个赛车条件。有时它会起作用,有时会返回分段错误。

我用bug写了一个最小的代码示例。

这是我的队列代码

//####################
// 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错误:         new-&gt; seq =(char *)malloc((n + 1)* sizeof(char));

*检测到glibc * / home / pedro / Dropbox /Programação/ C / Queue / fila_teste:double free或corruption(out):0x00000000006f3bd0 * 检测到 glibc / home / pedro / Dropbox /Programação/ C / Queue / fila_teste:malloc():内存腐败(快速):0x00000000006f3b70 *

2 - new_queu_item()行上的malloc错误:         new =(QueueItem *)malloc(sizeof(QueueItem));

3 - seq_to_file()行没有错误:             自由(SEQ);

*检测到glibc * / home / pedro / Dropbox /Programação/ C / Queue / fila_teste:double free或corruption(out):0x0000000000cdd3f0 *

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

这第三个错误让我觉得这确实是一种竞争条件。

我尝试使用“end_flag”模拟信号量,但不认为这是足够的。另外,不要认为“关键”和“原子”条款在这里会有所帮助,因为它们只保护代码区域的访问,而不是内存。

知道如何解决这个问题吗?

1 个答案:

答案 0 :(得分:1)

如果您不打算重复使用此代码,可以使用以下命令:

#pragma omp critical(queueLock)

在上面的例子中,该指令将充当“命名”互斥锁“queueLock”。在这种情况下,您必须在enqueue,dequeue和queue_size函数中使用它,因为它们都使用共享数据。

如果您打算重用此代码,您应该了解OpenMP锁(omp_lock_t)。