0

uI believe my logic is correct from my understanding of semaphores. It is the producer/consumer problem. Producer generates a random letter, decrements empty buffer by 1, decrements mutex to get permission to enter its critical section, then within the critical section it adds the random letter to the buffer, thereafter increments mutex, then increments full. Consumer waits until full is greater than 0, decrements mutex to see if it can enter its critical section, within the critical section the random letter will be taken from the buffer and will do some calculations, then it will increment mutex and increment empty.

The problem I'm having is that I keep getting different outputs when I run the program. There seems to be no order in which I get them. Some of the outputs are correct and some are wrong. Why am I getting different outputs? Here is my code and outputs:

#include <iostream>
#include <pthread.h>
#include <string>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <semaphore.h>
#include <cstring>
using namespace std;

void* consumer(void*);
void* producer(void*);

string buffer[3];
int put = 0;
int get = 0;
sem_t mutex;
sem_t empty;
sem_t full;
int pw = 0;
int cw = 0;
string alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

int main() {

    sem_init(&mutex, 0, 1);
    sem_init(&empty, 0, 3);
    sem_init(&full, 0, 0);

    pthread_t consumerThread;
    pthread_t producerThread;
    pthread_create(&producerThread, NULL, &producer, NULL);
    pthread_create(&consumerThread, NULL, &consumer, NULL);
    pthread_join(producerThread, NULL);
    pthread_join(consumerThread, NULL);

    sem_destroy(&mutex);
    sem_destroy(&empty);
    sem_destroy(&full);  

    return 0;
  }

void* producer(void*) {

  while (pw < 6) {
    pw++;

    //srand(time(NULL));
    int a1 = rand() % 25;
    cout << "producer: " << alpha[a1] << endl;

    sem_wait(&empty);
    sem_wait(&mutex);

    buffer[put] = alpha[a1];
    put = (put + 1) % 3;

    sem_post(&mutex);
    sem_post(&full);

    }
    return 0;
    }

void* consumer(void*) {

  while (cw < 6) {
    cw++;

    sem_wait(&full);
    sem_wait(&mutex);       

    string c = (1, buffer[get]);
    buffer[get] = "";
    get = (get + 1) % 3;

    int a;
    int v1;
    int v2;
    int d1;
    int d2;
    string S;
    string T;
    for (int i = 0; i < alpha.length(); i++) {
        if (alpha[i] == c[0]) {
            a = i;
        }
    }

    if (a % 2 == 0) {

        if (a == 0) {
            v1 = 20;
            v2 = 4;
        } else if (a > 0 && a < 4) {
            v1 = 0;
            v2 = 4;
        } else if (a == 4) {
            v1 = 0;
            v2 = 8;
        } else if (a > 4 && a < 8) {
            v1 = 4;
            v2 = 8;
        } else if (a == 8) {
            v1 = 4;
            v2 = 14;
        } else if (a > 8 && a < 14) {
            v1 = 8;
            v2 = 14;
        } else if (a == 14) {
            v1 = 8;
            v2 = 20;
        } else if (a > 14 && a < 20) {
            v1 = 14;
            v2 = 20;
        } else if (a == 20) {
            v1 = 14;
            v2 = 0;
        } else if (a > 20 && a <= 25) {
            v1 = 20;
            v2 = 0;
        } else {
            cout << "error with v1 and v2, incorrect index" << endl;
        }

        S = alpha[v1] + c + alpha[v2];

        if (v1 > a) {
            d1 = a - v1 + 26;
        } else {
            d1 = a - v1;
        }

        if (a > v2) {
            d2 = (25 - v2) % 25;
        } else {
            d2 = v2 - a;
        }

        if (d1 > d2) {
            T = alpha[v1] + S + alpha[v1];
        } else if (d2 > d1) {
            T = alpha[v2] + S + alpha[v2];
        } else {
            //cout << "Both distances are the same." << endl;
        }

        cout << alpha[a] << alpha[v1] << alpha[v2] << S << " - c to v1: " << d1 << " - c to v2: " << d2 << endl;           

        if (d1 > d2) {
            cout << "The distance from c to v1 is larger: " << d1 << endl;
        } else if (d2 > d1) {
            cout << "The distance from c to v2 is larger: " << d2 << endl;
        } else {
            cout << "The distances are the same: " << d1 << endl;
        }

        //testing
        //cout << "v1: " << v1 << endl;
        //cout << "v2: " << v2 << endl;
        //cout << "d1: " << d1 << endl;
        //cout << "d2: " << d2 << endl;

    } else {
        cout << "consumer: " << alpha[a] << endl;
    }
    sem_post(&mutex);
    sem_post(&empty);
}

return 0;
}

Outputs:

output 1:

producer: I
producer: L
producer: C
producer: P
IEOEIO - c to v1: 4 - c to v2: 6
The distance from c to v2 is larger: 6
consumer: L
CAEACE - c to v1: 2 - c to v2: 2
The distances are the same: 2
producer: S
consumer: P
producer: K
SOUOSU - c to v1: 4 - c to v2: 2
The distance from c to v1 is larger: 4
KIOIKO - c to v1: 2 - c to v2: 4
The distance from c to v2 is larger: 4

RUN FINISHED; exit value 0; real time: 0ms; user: 0ms; system: 0ms

output 2:

producer: I
producer: L
IEOEIO - c to v1: 4 - c to v2: 6
The distance from c to v2 is larger: 6
producer: C
consumer: L
producer: P
CAEACE - c to v1: 2 - c to v2: 2
The distances are the same: 2
producer: S
consumer: P
producer: K
SOUOSU - c to v1: 4 - c to v2: 2
The distance from c to v1 is larger: 4
KIOIKO - c to v1: 2 - c to v2: 4
The distance from c to v2 is larger: 4

RUN FINISHED; exit value 0; real time: 0ms; user: 0ms; system: 0ms

It seems like the buffer is working fine as everything put inside is coming out and not being deleted or ignored, but there should never be 4 producer outputs in a row as this would go over the buffer size(3). Also consumer does replace the value in value with empty, so I believe this may be a syncing error I'm having. Again thank you for the input.

  • Tags C++11.. uses `pthreads`.. Unnamed function parameters.. – Brandon Nov 26 '17 at 20:50
  • My apologies. I will fix it – Adam Herritt Nov 26 '17 at 20:53
  • You have syntax errors.. `string c = (1, buffer[get]);` should be: `string c(buffer[get], 1);` or `string c = string(buffer[get], 1);` Then you will see an exception being thrown. – Brandon Nov 26 '17 at 21:05
  • This does not appear to be a syntax error as I am not getting a syntax error nor is it causing any problems in my program. But I will try it, though this would not be effecting my order of output. Also what unnamed function parameters? none of my functions require parameters. – Adam Herritt Nov 26 '17 at 21:19
  • Your function signatures are: `void* consumer(void*)`.. which states: this function takes a void pointer as a parameter and returns a void pointer. – Brandon Nov 26 '17 at 21:22
  • This is what I was taught was normal syntax, that if you are not passing in a parameter you still need void*, but you do not need to name the parameter since it is unused. Perhaps it is considered proper formality to name the unused parameter, but it is not logically nor syntactically incorrect from my knowledge and testing. – Adam Herritt Nov 26 '17 at 21:32
  • Whoever told you that, you should stop listening to them.. You are coding C++, not C. It is proper to put `void` as the parameter in C if the function takes no arguments.. NOT `void*`. One means "nothing". The other means `opaque pointer` (pointer to anything). In C++, you don't put void as a parameter. You can, but you don't need to. See here: https://stackoverflow.com/questions/416345/is-fvoid-deprecated-in-modern-c-and-c – Brandon Nov 27 '17 at 01:23

1 Answers1

1

You are printing before critical section in producer. So, it can print 4 times and then stop on semaphore, while only 3 elements are in buffer. And only after consumer consumes one of those 3 elements next element is put into buffer.

nowaqq
  • 261
  • 3
  • 10
  • This seems like it could be the problem. Thank you. I will fix it and see what I get. Even still, why would I be getting different outputs on some runs? – Adam Herritt Nov 26 '17 at 21:07
  • Because there is no guarantee on order of execution of two threads (other than, in your case, it won't be in critical section guarded by mutex simultaneously). Also, in your code you don't check in consumer if there are any elements in the buffer before you get one from it. You didn't hit this, but it is possible, that consumer will try to get element from buffer before producer put it there (in particular, when buffer is empty). – nowaqq Nov 26 '17 at 21:21
  • I have fixed it so that the producer output takes place immediately before it is added to the buffer(after my waits). My outputs are correct now, but 1 in every 15 runs or so is giving a different output (as in the ordering is different but still appears to be correct). Shouldn't the program run the same every single time? ahh you just answered my question thank you very much for the input. I may be wrong in my logic, but I shouldn't have to check in consumer if the buffer is empty because of my "full" semaphore. – Adam Herritt Nov 26 '17 at 21:23