OpenMP Producer-Consumer意外结果

时间:2013-11-18 05:54:26

标签: c multithreading openmp producer-consumer

我正在研究一个简单的生产者 - 消费者问题,在C中使用OpenMP。

我的程序创建了4个线程,其中两个是消费者,两个是生产者。每个制作人将一个角色放在缓冲区中,消费者只需打印该角色。

我的目标是同步生产者/消费者,以便每个生产者将生成字母表中的下一个按顺序字符,并且每个消费者将打印放置在缓冲区中的下一个按顺序字符。

这是我的代码:

#include <stdio.h>
#include <unistd.h>
#include <omp.h>

#define SIZE 5
#define NUMITER 26


char buffer[SIZE];
int nextin = 0;
int nextout = 0;
int count = 0;
int empty = 1;
int full = 0;
int i,j;

void put(char item)
{
    buffer[nextin] = item;
    nextin = (nextin + 1) % SIZE;

    count++;
    if (count == SIZE)
        full = 1;
    if (count == 1) // buffer was empty
        empty = 0;
}


void producer(int tid)
{
    char item;
    while( i < NUMITER)
    {
        #pragma omp critical
        {
            item = 'A' + (i % 26);
            put(item);
            i++;
            printf("%d Producing %c ...\n",tid, item);
        }
        sleep(1);
    }
}


char get()
{
    char item;

    item = buffer[nextout];
    nextout = (nextout + 1) % SIZE;
    count--;
    if (count == 0) // buffer is empty
        empty = 1;
    if (count == (SIZE-1))
        // buffer was full
        full = 0;
    return item;
}


void consumer(int tid)
{
    char item;
    while(j < NUMITER )
    {
        #pragma omp critical
        {
            j++;
            item = get();
            printf("%d ...Consuming %c\n",tid, item);
        }
    sleep(1);
    }
}

int main()
{
    int tid;
    i=j=0;
    #pragma omp parallel firstprivate(i,j) private(tid) num_threads(4) 
    {
       tid=omp_get_thread_num();

       if(tid%2==1)
       {
           producer(tid);
       }
       else
       {
           consumer(tid);
       }
    }
}

这是输出:

0 Producing A ...
2 Producing B ...
1 ...Consuming A
3 ...Consuming B
1 ...Consuming  <---- notice empty
0 Producing C ...
3 ...Consuming  <---- notice empty
2 Producing D ...
2 Producing E ...
3 ...Consuming E
0 Producing F ...
1 ...Consuming F
2 Producing G ...
3 ...Consuming G
0 Producing H ...
1 ...Consuming H
3 ...Consuming D
2 Producing I ...
0 Producing J ...
1 ...Consuming J
3 ...Consuming F
2 Producing K ...
0 Producing L ...
1 ...Consuming L
3 ...Consuming H
2 Producing M ...
0 Producing N ...
1 ...Consuming N
3 ...Consuming J
2 Producing O ...
0 Producing P ...
1 ...Consuming P
3 ...Consuming L
2 Producing Q ...
0 Producing R ...
1 ...Consuming R
2 Producing S ...
3 ...Consuming S
0 Producing T ...
1 ...Consuming T
3 ...Consuming P
2 Producing U ...
0 Producing V ...
1 ...Consuming V
2 Producing W ...
3 ...Consuming W
0 Producing X ...
1 ...Consuming X
2 Producing Y ...
3 ...Consuming Y
0 Producing Z ...
1 ...Consuming Z

那些没有打印字符的空行表示我没有实现我应该达到的同步。 我错过了什么?

提前感谢您的任何帮助或想法。

1 个答案:

答案 0 :(得分:1)

所以@Jlghtuse是正确的,有数据竞争,这是因为关键区域的错误声明。

你看我宣布我的关键领域:

void consumer(int tid)
{
    char item;
    while(j < NUMITER )
    {
        #pragma omp critical
        {
            j++;
            item = get();
            printf("%d ...Consuming %c\n",tid, item);
        }
    sleep(1);
    }
}

void producer(int tid)
{
    char item;
    while( i < NUMITER)
    {
        #pragma omp critical
        {
            item = 'A' + (i % 26);
            put(item);
            i++;
            printf("%d Producing %c ...\n",tid, item);
        }
        sleep(1);
    }
}

这导致消费者无法访问其他消费者关键区域,但产生了,反之亦然。解决方案相当简单,我只需要为关键区域添加一个通用名称,现在消费者的关键区域对于生产者来说也是至关重要的,反之亦然。

这是用于声明关键区域的正确代码:

#pragma omp critical (CRIT)