Home > database >  Multithreading Web Server pThread Issue
Multithreading Web Server pThread Issue

Time:03-06

I am working on a project that simulates client requests and runs a process from a different file (this process was given to me, so I'm not supposed to edit it).

I have to use the producer-consumer method for this problem and use semaphores and a mutex lock to ensure no deadlocking, etc. I am running into the issue that my threads don't seem to realize when there is a connection and aren't triggered to complete the jobs on the server. The program creates the threads successfully, but I think I'm just missing something or not understanding the basics of how all the things I mentioned above work together. I want to understand the logic of what triggers a thread to begin working and how that makes sense with a listener / socket system waiting on a client connection. Here is a breakdown of the code, I don't want to include all of it, just the frameworks of how it all works.

#define MAX_REQUEST 100

int port, numThread;
typedef int bufferItem;
bufferItem buffer[MAX_REQUEST]; // shared buffer
int bufferIndex;
bool connection = false;
pthread_t threads[MAX_REQUEST];
sem_t full;
sem_t empty;
pthread_mutex_t mutex;

int insertItem(bufferItem item) {
    // This method adds the item in the argument to the buffer and increments the buffer index.
    if(bufferIndex < MAX_REQUEST) {
        buffer[bufferIndex] = item;
        bufferIndex  ;
        return(0); // success
    }
    else {
        return(-1); // error
    }
}

int removeItem() {
    bufferItem item;
    if(bufferIndex > 0) {
        bufferIndex--;
        item = buffer[bufferIndex];

        process(item); // run process (outside method) HERE

        return(0); // success
    }
    else {
        return(-1); // error
    }  
}

int req_handler() {
    // this method opens a socket and starts HTTP server listening on port
    // after connection to client is successful, following code executes
    while (1) {
        int s;
        s = accept(sock, NULL, NULL);
        if (s < 0) break;
        bool connection = true;
        printf("Connected!\n");

        //put in request for info (file descriptor) into shared buffer
        insertItem(s);
        sem_post(&empty); // I think I may have an error here, I have tried different things to trigger the thread but nothing works
    }
    // socket is closed
}

void *producer (void *arg) {
    // tests if there is a connection using a boolean
    // decrements buffer with empty semaphore
    // locks mutex
    int ret = insertItem(gettid()); // put item in buffer
    // unlocks mutex so other threads can use
    // increments buffer with full semaphore
}

void *consumer (void *arg) {
    // tests if there is a connection using a boolean
    // decrements full semaphore
    // locks mutex
    int ret = removeItem(); // put item in buffer
    // unlocks mutex
    // increments buffer with empty semaphore
}

int main(int argc, char *argv[]) {
    // sets up command line arguments to get port number and number of threads
    // initializes semaphores and mutex
    pthread_mutex_init(&mutex, NULL);
    sem_init(&empty, 0, MAX_REQUEST);
    sem_init(&full, 0, 0);

    int threadNum[numThread]; // keep track of threads

    for (i = 0; i < numThread; i  ) { // create threads
        threadNum[i] = i;
        if (i == 0) {
            if(pthread_create(&threads[i], NULL, producer, (void *)&threadNum[i]) != 0) {
                perror("Producer: Thread creation error");
            }
        } else {
            if(pthread_create(&threads[i], NULL, consumer, (void *)&threadNum[i]) != 0) {
                perror("Consumer: Thread creation error");
            }
        }
        printf("Main: Thread Created :)\n");
    }

    // wait until all threads have exited (joined)
    for(i = 0; i < numThread; i  ) {
        printf("Main: Thread Joined with numThread: %d and i %d \n",numThread,i);
        if(pthread_join(threads[i], NULL) != 0) {
            perror("Main: Thread join error");
        } 
    }

    req_handler(); // starts listener

    printf("All threads joined, destrying semaphores and mutex :)\n");

    // destroys semaphores and mutexes

    return 0;
}

CodePudding user response:

Your semaphores are going unused. This isn't a coding issue, but an understanding issue, and I'll answer it as such.

I'll be explaining it as if storage can contain more than one (n) item, but this works even if storage can only accommodate one item. Similarly, I'll be explaining it as there are multiple producers (p) and multiple consumers (c), but this works even if there are only one of each. However, if n=1, p=1 and c=1, there's no need for the mutex.


The flow of data is:

Producers -> Storage -> Consumers

In order to achieve this,

  • A consumer needs to wait for data to become available in storage.
  • A producer needs to wait for space to become available in storage.

This can be achieved using two semaphores:

  • One that keeps track of the number of items in storage.
  • One that keeps track of the amount of free space in storage.

Logic:

  • Initially:

    • There are 0 items in storage.
    • There are n spaces for items.
  • When a producer wants to add an item:

    • They must wait for space to become available.
  • After a producer produces an item:

    • They must signal this by increasing the number of items in storage.
  • When a consumer wants to consume an item:

    • They must wait for an item to become available.
  • After a consumer consumes an item:

    • They must signal this by increasing the amount of space in storage.

These correspond to the init, down/wait and up/post operations of the two semaphores.

A mutex is used when actually reading/modifying the storage (once the semaphore has indicated it's in the desired state).

  • Related