Segmentation Fault when using Threads and Semaphores, Mac Vs Linux
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!
Admin
Updated on June 09, 2022Comments
-
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); } }