Semaphore issue in C++ multithreaded program

77 views Asked by At

I'm working on a C++ program that simulates Conway's Game of Life using multithreading and semaphores for synchronization. However, I'm encountering issues with the semaphores not working properly.

I have a Cell class representing each cell in the game, and each cell communicates with its neighbors using semaphores to exchange state information. Here's a simplified version of the relevant code:


class Cell {
private:
    struct CellMessage {
        Cell *neighbor;
        Cell *caller;
        bool state;
    };

    std::vector<bool> buffer;
    int capacity;
    sem_t empty;
    sem_t full;
    sem_t mutex;

    static void* send_message_neighbor(void* curr_cell) {
        CellMessage* c = static_cast<CellMessage*>(curr_cell);

        // wait if the buffer is full
        sem_wait(&c->neighbor->empty);
        sem_wait(&c->neighbor->mutex); 
        c->neighbor->buffer.push_back(c->state);
        sem_post(&c->neighbor->mutex);  // Release mutex
        // Signal that a new item is produced
        sem_post(&c->neighbor->full);

        return NULL;
    }

public:
    std::vector<Cell*> neighbors;
    int row = 0;
    int col = 0;
    bool state;

    Cell() {}

    Cell(bool s, int r, int c) : state(s), capacity(r + 1), row(r), col(c) {
        sem_init(&empty, 0, r+1);
        sem_init(&full, 0, 0);
        sem_init(&mutex, 0, 1); // Initialize mutex semaphore
    }

    void send_message_neighbors() {
        pthread_t tneighbors[neighbors.size()];

        for (size_t i = 0; i < neighbors.size(); ++i) {
            CellMessage* cl = new CellMessage();
            cl->neighbor = neighbors[i];
            cl->caller = this;
            cl->state = state;

            pthread_create(&tneighbors[i], NULL, send_message_neighbor, cl);
        }

        for (size_t i = 0; i < neighbors.size(); ++i) {
            pthread_join(tneighbors[i], NULL);
        }
    }
   };

The problem I'm facing is that multiple threads seem to be able to access the semaphore-controlled buffer simultaneously, causing unexpected behavior. I've tried using semaphores to control access to the buffer, but it doesn't seem to be working as expected. To consume the state of the neighboors cell, I had this method (To consume the state of the neighboring cells, I have this method. (I know there may be better ways to do it, but this is just a first version. I only want to focus on understanding the proper use of semaphores.):

void compute_state() {
        int amount_alive_neighbors = 0;

        while (!buffer.empty()) {
            sem_wait(&full);

            if (*buffer.begin()) {
                amount_alive_neighbors++;
            }
            buffer.erase(buffer.begin());

            sem_post(&empty);
        }

        if (state) {
            if (amount_alive_neighbors > 3 || amount_alive_neighbors == 0) {
                state = false;
            }
        } else {
            if (amount_alive_neighbors == 3) {
                state = true;
            }
        }
    }

The board method that triggers all the process each generation is as follows in my code:


void compute_cell_neighbors() {
        for (int i = 0; i < MATRIX_SIZE; i++) {
            for (int j = 0; j < MATRIX_SIZE; j++) {
                m[i][j]->neighbors = identify_neighbors(i, j);
                m[i][j]->send_message_neighbors();
                m[i][j]->compute_state();
            
            }
        }
    }

Could someone please review my code and help me understand if semaphores are being handled correctly? Additionally, any suggestions on how to fix the semaphore issue would be greatly appreciated.

Thank you!

0

There are 0 answers