2016-10-27 5 views
1

Я написал программу, состоящую из четырех потоков. Первый для инициализации остальных, второй для создания элементов и добавления их в буфер, третий для добавления элементов в другой буфер и четвертый для потребления элементов из любого буфера. Моя проблема в том, что четвертый поток читает из буферов, прежде чем они будут записаны. Я поставил семафоры в попытке синхронизировать, но они не выполняют, как я ожидал.Ошибка многопоточной синхронизации источника питания/производителя

я упростил свой код, сохраняя при этом ошибку:

#include <stdlib.h> 
#include <stdio.h> 
#include <semaphore.h> 
#include <pthread.h> 
#include <sys/types.h> 

/* thread routines */ 
void* threadA(); 
void* threadB(); 
void* threadC(); 

/* thread ids */ 
pthread_t tid[3]; 

/* semaphores */ 
sem_t sA; 
sem_t sB; 
sem_t a_empty; 
sem_t b_empty; 
sem_t both_full; 
sem_t mutex; 

/* buffers */ 
int buffA[20]; 
int buffB[40]; 

/* int a for tracking buffA */ 
int a = 0; 

int main() 
{ 

/* initializing semaphores */ 
    sem_init (&a_empty, 20, 1); 
    sem_init (&b_empty, 40, 1); 
    sem_init (&both_full, 0, 1); 
    sem_init (&mutex, 1, 1); 
    sem_init (&sA, 0, 1); 
    sem_init (&sB, 0, 1); 

/* creating threads */ 
    pthread_create(&tid[0], NULL, threadA, NULL); 
    pthread_create(&tid[1], NULL, threadB, NULL); 
    pthread_create(&tid[2], NULL, threadC, NULL); 

/* waiting on threads */ 
    pthread_join(tid[0], NULL); 
    pthread_join(tid[1], NULL); 
    pthread_join(tid[2], NULL); 
} 

/* Producer */ 
void* threadA() 
{ 
int i; 
int inA = 0; 

/* two process two way synch*/ 
sem_post(&sB); 
sem_wait(&sA); 

for (i = 1; i <= 300; i++) 
{ 

/* adding item to buffer */ 
    sem_wait(&a_empty); 
    buffA[inA] = i; 

/* incrementing a */ 
    sem_wait(&mutex); 
    a = a + 1; 
    sem_post(&mutex); 

/* signaling full buffer */ 
    sem_post(&both_full); 

/* updating inA */ 
    inA = (inA + 1) % 20; 

} 

pthread_exit(NULL); 
} 

/* Producer */ 
void* threadB() 
{ 
int i, j, inB; 
inB = 0; 

/* two process two way synch*/ 
sem_post(&sA); 
sem_wait(&sB); 

for(i = 1; i <= 400; i++) 
{ 

/* producing item. */ 
    sem_wait(&b_empty); 
    buffB[inB] = i; 

    sem_post(&both_full); 

    inB = (inB + 1) % 40; 
} 

pthread_exit(NULL); 
} 

/* Consumer */ 
void* threadC() 
{ 
int i, j, outA, outB, bsum, asum; 
outA = 0; 
outB = 0; 
asum = 0; 
bsum = 0; 
int prod_a; 
int prod_b; 

for(i = 0; i < 700; i++) 
{ 

    sem_wait(&both_full); 
    if (a > 0) { 
    asum++; 
    prod_a = buffA[outA]; 
    outA = (outA + 1) % 20; 
    sem_wait(&mutex); 
    a = a - 1; 
    sem_post(&mutex); 
    sem_post(&a_empty); 

    printf("A-%d\t", prod_a); 
    } 
    else { 
    bsum++; 

    prod_b = buffB[outB]; 
    outB = (outB + 1) % 40; 
    sem_post(&b_empty); 

    printf("B-%d\t", prod_b); 
    } 
} 

printf("\n a=%d b=%d \n", asum, bsum); 
pthread_exit(NULL); 
} 

Моя проблема, кажется, что это заявление еще в threadC() в настоящее время выполняется, когда оно не должно быть. Я не могу точно определить, что может вызвать это.

EDIT: Я использую gcc file.c -o file.o -lrt -lpthread компилировать

+1

Первый выпуск I см., я думаю, вы можете вызвать 'sem_init()' с неправильным порядком аргументов на 'a_empty' и' b_empty'. Начальное 'значение' должно быть третьим аргументом' int sem_init (sem_t * sem, int pshared, unsigned int value); ' –

+0

Что вы пытаетесь использовать с' sem_post ( sem_wait (&sA); '? –

+0

@LuisdeArquer В этом проблема. Я переключил аргументы для 'pshared' и' value', давая семафоры плохие начальные значения. 'Sem_post (sem_wait (&sA);)' так что потоки ожидают друг друга перед запуском. –

ответ

1

Семафор both_full должен быть инициализирован со значением 0:

sem_init (&both_full, 0, 0); 

Обычно outB всегда должен быть равен или меньше, чем inB. Но с both_full, инициализированным до 1, оператор else в threadC() запускается в какой-то момент без ввода доступных данных, позволяя увеличить outB до inB+1. Таким образом, в первые 40 раз вы можете видеть нули (статические буферы обнуляются при запуске программы), после чего вы можете увидеть старые значения, такие как B-51 B-52 B-13 B-54