Segmentation Fault when using Threads and Semaphores, Mac Vs Linux

12,114

How to debug stuff like this

The best way to debug this is to run it using the gdb debugger. Like this:

gdb my-monkey-program
(gdb) run
Program received signal SIGSEGV, Segmentation fault.
(gdb) info threads
(gdb) bt

Another excellent idea is to run it with valgrind:

valgrind ./my-monkey-program

which will tell you about invalid memory accesses and all sorts of things.

Your specific problem

gdb reports that the call stack is:

#0  sem_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S:45
#1  0x0000000000400e8d in toAThread (threadId=0x602160) at test.c:190
#2  0x00007ffff7bc4e9a in start_thread (arg=0x7fffed7e9700) at pthread_create.c:308
#3  0x00007ffff78f1cbd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:112
#4  0x0000000000000000 in ?? ()

Here are the line numbers from my compile:

187     baboonOrder = "A ";
188     strcat(orderLeaving, baboonOrder);
189 
190     sem_wait(mutex);

This is because mutex is NULL.

Why it breaks

You're never actually assigning to the mutex variable. You're passing a pointer into sem_open_errorCheck, but what you really need to pass is a pointer-to-a-pointer. Presumably the same applies to toA and toB.

It's just luck that it worked on the Mac!

Share:
12,114
Admin
Author by

Admin

Updated on June 09, 2022

Comments

  • Admin
    Admin almost 2 years

    My problem deals with a segmentation fault that I get when I run this program on a linux machine versus my own mac computer. This program runs how I believe it should on my own mac computer, yet when I try to run it on my school's linux computers, I get a segmentation fault that doesn't appear on my mac computer. I'll give a brief background on the assignment and then go over the problem in more detail.

    So I have this program which basically simulates baboons crossing a ravine with a single rope. Only one baboon can cross at a time and there are certain restraints on the number of baboons that can cross at a time, as well as how many baboons can cross from one direction before baboons from the other direction are allowed to cross. The implementation of the code.

    I have searched for segmentation fault questions already here on stackoverflow, yet most of them deal with multiple processes whereas I am merely using different threads. The segmentation fault ends up coming from waiting on a semaphore that doesn't exist, yet when I checked to see whether it was initialized, it was successfully initialized. Again, this program works on my mac but then doesn't work when I try to run it on my Mac. Any help at all understanding why it can't run on the linux machines but can run on the mac. If any more information is needed, I would be happy to provide it. I did error check at one point but that code was deleted off the school computers. My error checking, as far as I remember, didn't show any errors.

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <sys/time.h>
    #include <time.h>
    #include <pthread.h>
    
    #include <semaphore.h>
    #include <fcntl.h>
    #include <sys/stat.h> //for mode flags, if needed for future use
    
    #define ATOB_COUNT 20
    #define BTOA_COUNT 20
    #define RANDOM_SEED 2123
    
    //semaphore names
    #define MUTEX_SEM "/mutex"
    #define TOB_SEM "/toB"
    #define TOA_SEM "/toA"
    
    //define methods here if needed
    void *toAThread(void *threadId);
    void *toBThread(void *threadId);
    void my_sleep(int limit);
    void sem_open_errorCheck(char *name, unsigned int startingValue, sem_t *result);
    
    //defining semaphores and shared variables
    sem_t *mutex, *toB, *toA;
    int xingCount = 0;
    int xedCount = 0;
    int toBWaitCount = 0;
    int toAWaitCount = 0;
    enum xingDirectionTypes {
        none,
        aToB,
        bToA
    };
    enum xingDirectionTypes xingDirection = none;
    
    char orderLeaving[100];
    
    
    struct threadInfo {
        int threadId;
    };
    
    struct threadInfo atobIDs[ATOB_COUNT];
    struct threadInfo btoaIDs[BTOA_COUNT];
    
    int main(void) {
    
        pthread_t atobPTHREADS[ATOB_COUNT];
        pthread_t btoaPTHREADS[BTOA_COUNT];
        pthread_attr_t attr;
        void *status;
    
        srandom(RANDOM_SEED);
    
        //call helper method which creates semaphore and errorchecks
        sem_open_errorCheck(MUTEX_SEM, (unsigned int)1, mutex);
        sem_open_errorCheck(TOA_SEM, (unsigned int)0, toA);
        sem_open_errorCheck(TOB_SEM, (unsigned int)0, toB);
    
    
        //Creating a set of attributes to send to the threads
        pthread_attr_init(&attr);
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
    
        //spawn toB baboons
        int counter;
        for (counter = 0; counter < BTOA_COUNT; counter++) {
            atobIDs[counter].threadId = counter;
            int result;
            if ((result = pthread_create(&atobPTHREADS[counter], &attr, toBThread, (void*) &atobIDs[counter])) == -1) {
                perror("Thread Creation Error: atob baboon");
                exit(EXIT_FAILURE);
            }
        }
    
        //spawn toA baboons
        for (counter = 0; counter < ATOB_COUNT; counter++) {
            btoaIDs[counter].threadId = counter + 20;
            int result;
            if ((result = pthread_create(&btoaPTHREADS[counter], &attr, toAThread, (void*) &btoaIDs[counter])) == -1) {
                perror("Thread Creation Error: btoa baboon");
                exit(EXIT_FAILURE);
            }
        }
    
        //Wait for all the threads to finish
        for(counter = 0; counter < ATOB_COUNT; counter++)
        {
            int result = pthread_join(atobPTHREADS[counter], &status);
            if(result == -1)
            {
                perror("Thread Join: AtoB");
                exit(EXIT_FAILURE);
            }
        }
    
        for(counter = 0; counter < BTOA_COUNT; counter++)
        {
            int result = pthread_join(btoaPTHREADS[counter], &status);
            if(result == -1)
            {
                perror("Thread Join: BtoA");
                exit(EXIT_FAILURE);
            }
        }
        printf("The order leaving %s", orderLeaving);
        exit(EXIT_SUCCESS);
    }
    
    void *toBThread(void *threadId) {
    
        struct threadInfo *info;
        info = (struct threadInfo *)threadId;
        int id = info->threadId;
    
        my_sleep(100); //simulate being idle for 1-100ms
        //for order checking
        char *baboonOrder;
        baboonOrder = "B ";
        strcat(orderLeaving, baboonOrder);
    
        sem_wait(mutex);
        if ((xingDirection == aToB || xingDirection == none) && xingCount < 5 && (xedCount + xingCount) < 10) { //there is an extra parenthesis here in the solutions
            xingDirection = aToB;
            xingCount++;
            printf("AtoB baboon (thread %d) got on the rope\n", id);
            sem_post(mutex);
        }
        else {
            toBWaitCount++;
            sem_post(mutex);
            sem_wait(toB);
            toBWaitCount--;
            xingCount++;
            xingDirection = aToB;
            printf("AtoB baboon (thread %d) got on the rope\n", id);
            sem_post(mutex);
        }
        //CROSSING
    
    
        sem_wait(mutex);
        printf("AtoB baboon (thread %d) got off the rope\n", id);
        xedCount++;
        xingCount--;
        if (toBWaitCount != 0 && (((xedCount+xingCount)<10) || ((xedCount+xingCount) >= 10 && toAWaitCount == 0))) {
            sem_post(toB);
        }
        else {
            if (xingCount == 0 && toAWaitCount != 0 && (toBWaitCount == 0 || (xedCount + xingCount)>=10)) {
                xingDirection = bToA;
                xedCount = 0;
                sem_post(toA);
            }
            else {
                if (xingCount == 0 && toBWaitCount == 0 && toAWaitCount == 0) {
                    xingDirection = none;
                    xedCount = 0;
                    sem_post(mutex);
                }
                else {
                    sem_post(mutex);
                }
            }
        }
    }
    
    /*
     baboons going from side a to side b
     */
    void *toAThread(void *threadId) {
    
        struct threadInfo *info;
        info = (struct threadInfo *)threadId;
        int id = info->threadId;
    
        my_sleep(100);
    
        //for order checking
        char *baboonOrder;
        baboonOrder = "A ";
        strcat(orderLeaving, baboonOrder);
    
        sem_wait(mutex);
        if ((xingDirection == bToA || xingDirection == none) && xingCount < 5 && (xedCount + xingCount) < 10) { //there is an extra parenthesis here in the solutions
            xingDirection = bToA;
            xingCount++;
            printf("BtoA baboon (thread %d) got on the rope\n", id);
            sem_post(mutex);
        }
        else {
            toAWaitCount++;
            sem_post(mutex);
            sem_wait(toA);
            toAWaitCount--;
            xingCount++;
            xingDirection = bToA;
            printf("BtoA baboon (thread %d) got on the rope\n", id);
            sem_post(mutex);
        }
        //CROSSING
    
    
        sem_wait(mutex);
        printf("BtoA baboon (thread %d) got off the rope\n", id);
        xedCount++;
        xingCount--;
        if (toAWaitCount != 0 && (((xedCount+xingCount)<10) || ((xedCount+xingCount) >= 10 && toBWaitCount == 0))) {
            sem_post(toA);
        }
        else {
            if (xingCount == 0 && toBWaitCount != 0 && (toAWaitCount == 0 || (xedCount + xingCount)>=10)) {
                xingDirection = aToB;
                xedCount = 0;
                sem_post(toB);
            }
            else {
                if (xingCount == 0 && toAWaitCount == 0 && toBWaitCount == 0) {
                    xingDirection = none;
                    xedCount = 0;
                    sem_post(mutex);
                }
                else {
                    sem_post(mutex);
                }
            }
        }
    }
    
    //taken with permission from readers/writers problem
    //Puts the calling thread to sleep to simulate both random start times and random workloads
    void my_sleep(int limit) {
        struct timespec time_ns;
        int duration = random() % limit + 1;
        time_ns.tv_sec = 0;
        time_ns.tv_nsec = duration * 1000000;
        int result = nanosleep(&time_ns, NULL);
        if (result != 0)
        {
            perror("Nanosleep");
            exit(EXIT_FAILURE);
        }
    }
    
    void sem_open_errorCheck(char *name, unsigned int startingValue, sem_t *result) {
    
        sem_unlink(name);
        result = sem_open(name, O_CREAT, 0600, startingValue);
        if (result == -1) {
            perror("sem_open error: semaphore failed to open correctly");
            exit(EXIT_FAILURE);
        }
    }