0
votes

I've got a program which has 10 Guest threads, 1 check-in thread, and 1 check-out thread. All threads are created using pthread_create() within my Main() method.

The whole thing runs well until the end where the Main() method is supposed to pthread_join() with the line pthread_join(desk[1], NULL); at which time a Segmentation Fault (core dumped) error is thrown.

I know it gets to that point because of the output I see in the console.

I use gcc -pthread FileName.c and ./a.out to compile and execute.

Can you see why I get an error at that point in my code?

The entire program is posted below:

//Hotel Project 
//This project creates a system to simulate a hotel.

#include <semaphore.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM_GUESTS  5 //10 guests

/*GLOBAL VARIABLE*/ int globalVar0; // Check-in guestID
/*GLOBAL VARIABLE*/ int globalVar1; // Check-out guestID
/*GLOBAL VARIABLE*/ int globalVar2; // Check-out room

void *CheckIn(void *); // the two threads
void *CheckOut(void *);

pthread_t guests[NUM_GUESTS];
pthread_t desk[2];

sem_t roomSem;              //total number of rooms in the hotel
sem_t check_in, check_out;  //reception desks
sem_t s1, s2, s3, s4, s5, s6;   //global semaphores
sem_t roomArraySem;
sem_t randSem;

int rooms[5] = {1,1,1,1,1}; //keep track of availability of each room

int total_guests;       //incremented with each guest check-out
int pool;               //incremented with each guest use pool
int resturant;          //incremented with each guest use resturant
int fitness_center;     //incremented with each guest use fitness center
int business_center;    //incremented with each guest use business center

struct thread_data
{
    int guest_id;   // id number of guest
    int room;       // room guest utilizes
    int event;      // 0=swim, 1=resturaunt, 2=fitness, 3=business
    int cost;       // final cost of stay (random value)
};

struct thread_data thread_data_array[NUM_GUESTS]; // array initialization

void *Guest(void *guestData)
{
    int guestid, guestroom, gevent, gcost, sleepVal;
    struct thread_data *guest_data;

    guest_data = (struct thread_data *) guestData;

    guestid = guest_data->guest_id; // guest_id stored in struct

    sem_wait(&roomSem);

    /*output*/ printf("Guest %d waits for check-in\n", guestid);
    sem_wait(&check_in); // if there is a room available, guest approaches check_in clerk; making him busy
        /*output*/ printf("Guest %d goes to the check-in reservationist\n", guestid);
        globalVar0 = guestid;
        sem_post(&s1);  // event ordering
        sem_wait(&s2);  // event ordering
        guestroom = guest_data->room;   // gets room value from struct
        /*output*/ printf("Guest %d receives Room %d and completes check-in\n", guestid, guestroom);
    sem_post(&check_in); // event ordering. Check-In now available

    sem_wait(&randSem);
    gevent = getRandomLessThan(4);  // activity connected to 0, 1, 2, 3
    printf("\tEvent: %d\n", gevent);
    sem_post(&randSem);
    printf("Guest: %d\tEvent: %d\n", guestid, gevent);
    guest_data[guestid].event = gevent; // assign to Guest's struct

    switch(gevent)
    {
        case(0):
            /*output*/ printf("Guest %d: Go to hotel swimming pool\n", guestid);
            pool++;
            break;

        case(1):
            /*output*/ printf("Guest %d: Go to hotel resturant\n", guestid);
            resturant++;
            break;

        case(2):
            /*output*/ printf("Guest %d: Go to hotel fitness center\n", guestid);
            fitness_center++;
            break;

        case(3):
            /*output*/ printf("Guest %d: Go to hotel business center\n", guestid);
            business_center++;
            break;
    }

    sem_wait(&randSem);
    sleepVal = getRandomLessThan(3) + 1;
    printf("\tSleepVal: %d\n", sleepVal);
    sem_post(&randSem);
    printf("Guest %d sleeps for %d seconds\n", guestid, sleepVal);
    sleep(1); // 0-2 + 1 = 1-3 //Change back

    /*output*/ printf("Guest %d waits for check-out\n", guestid);
    sem_wait(&check_out); // guest waits for check-out desk to be available
        /*output*/ printf("Guest %d goes to the check-out reservationist and returns room %d\n", guestid, guestroom);
        globalVar1 = guestid;
        //globalVar2 = guestroom;
        sem_post(&s3); // event ordering
        sem_wait(&s4); // event ordering

        gcost = guest_data[guestid].cost;
        /*output*/ printf("Guest %d receives the total balance of $%d\n", guestid, gcost);
        /*output*/ printf("Guest %d makes a payment\n", guestid);
        sem_post(&s5); // event ordering
        sem_wait(&s6); // event ordering
    sem_post(&check_out);

    total_guests++;

    pthread_exit(NULL);
}

int getRandomLessThan(int x)
{
    int r = -1;
    srand(time(NULL));
    r = rand() % x;
    //printf("\tRandom number: %d\n", r);

    return r;
}

int GetOpenRoom()
{
    int i;
    for (i=0; i<5; i++) // rooms.size and rooms.length throw errors
    {
        if (rooms[i] == 1) // room available
        {
            rooms[i] = 0; // set to unavailable
            return i;
        }
    }
}

int RoomAvailable()
{
    int i;
    for (i=0; i<5; i++)
    {
        if (rooms[i] == 1) // room available
            return 1;
    }
    return 0; // if none available, return 0
}

void *CheckIn(void *guestData)
{
    int i, guestid, guestroom;

    for(i=0; i<NUM_GUESTS; i++)
    {
        sem_wait(&s1); // event ordering

        guestid = globalVar0; // get the global variable set to the guestID
        /*output*/ printf("The check-in reservationist greets Guest %d\n", guestid);

        sem_wait(&roomArraySem);
        guestroom = GetOpenRoom(); // method returns index of open room
        sem_post(&roomArraySem);
        thread_data_array[guestid].room = guestroom; // assign room to guest

        /*output*/ printf("Assign room %d to Guest %d\n", guestroom, guestid);

        sem_post(&s2); // event ordering
    }

    pthread_exit(NULL);
}


void *CheckOut(void *guestData)
{
    int i, guestid, guestroom, gcost;

    for(i=0; i<NUM_GUESTS; i++)
    {
        sem_wait(&s3); // event ordering

        guestid = globalVar1;
        //guestroom = globalVar2;
        guestroom = thread_data_array[guestid].room;

        /*output*/ printf("The check-out greets Guest %d and receives the key from room %d\n", guestid, guestroom);
        sem_wait(&roomArraySem);
        rooms[guestroom] = 1; // room now available, set back to 1
        sem_post(&roomArraySem);
        sem_post(&roomSem); // release a room

        /*output*/ printf("Calculate the balance for Guest %d\n", guestid);
        gcost = getRandomLessThan(300) + 50;        // 50 < cost < 350
        thread_data_array[guestid].cost = gcost;

        sem_post(&s4); // event ordering
        sem_wait(&s5); // event ordering
        /*output*/ printf("Receive $%d from Guest %d and complete the check-out\n", gcost, guestid);
        sem_post(&s6); // event ordering
    }

    pthread_exit(NULL);
}



int main (int argc, char *argv[])
{
    int rc, rc1, rc2;
    int guest;
    int check;
    //struct thread_data *guest_data; //delete?

    sem_init(&roomSem, 1, 5); //not 0 means shared between multiple processes, 5 is initial value
    sem_init(&check_in, 1, 1);
    sem_init(&check_out, 1, 1);
    sem_init(&s1, 1, 0);
    sem_init(&s2, 1, 0);
    sem_init(&s3, 1, 0);
    sem_init(&s4, 1, 0);
    sem_init(&s5, 1, 0);
    sem_init(&s6, 1, 0);
    sem_init(&roomArraySem, 1, 1);
    sem_init(&randSem, 1, 1);

    rc1 = pthread_create(&desk[0], NULL, CheckIn, NULL);    // Check In runs on it's own now
    rc2 = pthread_create(&desk[1], NULL, CheckOut, NULL);   // Check Out runs on it's own now

    if(rc1){
        printf("ERROR; return code from desk0 is %d\n\n", rc);
        exit(-1);
    }
    if(rc2){
        printf("ERROR; return code from desk1 is %d\n\n", rc);
        exit(-1);
    }

    for(guest = 0; guest < NUM_GUESTS; guest++)
    {
        thread_data_array[guest].guest_id = guest; // guest ID for each guest thread
        /*Output*/printf("Main(): Creating Thread: %d\n", guest);
        rc = pthread_create(&guests[guest], NULL, Guest, (void *)&thread_data_array[guest]); //Guest method, &thread_data_array[guest] argument
        if (rc) {
            printf("ERROR; return code from pthread_create(Guest) is %d\n", rc);
            exit(-1);
        }
    }

    printf("\tDONE WITH THREADS\n");

    for(guest = 0; guest < NUM_GUESTS; guest++)
    {
        pthread_join(guests[guest], NULL); // waits for each guest to complete and cleans memory space
    }
    printf("\tBETWEEN THREAD JOINS 1\n");

    pthread_join(desk[0], NULL);
    printf("\tBETWEEN THREAD JOINS 2\n");
    pthread_join(desk[1], NULL);
    printf("\tBETWEEN THREAD JOINS 3\n");

    printf("\t\tNumber of Customers\n");
    printf("Total Guests:\t\t%d\n", total_guests);
    printf("Pool:\t\t\t%d\n", pool);
    printf("Resturant:\t\t%d\n", resturant);
    printf("Fitness Center:\t\t%d\n", fitness_center);
    printf("Business Center:\t%d\n", business_center);

    sem_close(&roomSem);
    sem_close(&check_in);
    sem_close(&check_out);
    sem_close(&s1);
    sem_close(&s2);
    sem_close(&s3);
    sem_close(&s4);
    sem_close(&s5);
    sem_close(&s6);
    sem_close(&roomArraySem);
    sem_close(&randSem);

}

Here's what the console returns:

tames@lab17:~/Desktop/project2$ gcc -pthread HotelProject_v4.c
tames@lab17:~/Desktop/project2$ ./a.out
Main(): Creating Thread: 0
Main(): Creating Thread: 1
Main(): Creating Thread: 2
Guest 1 waits for check-in
Main(): Creating Thread: 3
Guest 1 goes to the check-in reservationist
Main(): Creating Thread: 4
Guest 3 waits for check-in
The check-in reservationist greets Guest 1
Assign room 0 to Guest 1
Guest 2 waits for check-in
Guest 1 receives Room 0 and completes check-in
Guest 0 waits for check-in
Main(): Creating Thread: 5
Guest 4 waits for check-in
Guest 5 waits for check-in
Guest 3 goes to the check-in reservationist
Guest 1: Go to hotel fitness center
Guest 1 sleeps for 1 seconds
The check-in reservationist greets Guest 3
Assign room 1 to Guest 3
Main(): Creating Thread: 6
Guest 3 receives Room 1 and completes check-in
Main(): Creating Thread: 7
Guest 3: Go to hotel fitness center
Main(): Creating Thread: 8
Guest 6 waits for check-in
Guest 3 sleeps for 1 seconds
Guest 2 goes to the check-in reservationist
Guest 7 waits for check-in
Main(): Creating Thread: 9
Guest 8 waits for check-in
        DONE WITH THREADS
The check-in reservationist greets Guest 2
Assign room 2 to Guest 2
Guest 9 waits for check-in
Guest 2 receives Room 2 and completes check-in
Guest 2: Go to hotel fitness center
Guest 0 goes to the check-in reservationist
The check-in reservationist greets Guest 0
Assign room 3 to Guest 0
Guest 2 sleeps for 1 seconds
Guest 0 receives Room 3 and completes check-in
Guest 4 goes to the check-in reservationist
Guest 0: Go to hotel fitness center
The check-in reservationist greets Guest 4
Assign room 4 to Guest 4
Guest 0 sleeps for 1 seconds
Guest 4 receives Room 4 and completes check-in
Guest 4: Go to hotel fitness center
Guest 5 goes to the check-in reservationist
Guest 4 sleeps for 1 seconds
Guest 1 waits for check-out
Guest 1 goes to the check-out reservationist and returns room 0
The check-out greets Guest 1 and receives the key from room 0
Calculate the balance for Guest 1
The check-in reservationist greets Guest 5
Assign room 0 to Guest 5
Guest 1 receives the total balance of $0
Guest 1 makes a payment
Guest 5 receives Room 0 and completes check-in
Guest 5: Go to hotel fitness center
Guest 6 goes to the check-in reservationist
Receive $58 from Guest 1 and complete the check-out
Guest 5 sleeps for 2 seconds
Guest 3 waits for check-out
Guest 3 goes to the check-out reservationist and returns room 1
The check-out greets Guest 3 and receives the key from room 1
Calculate the balance for Guest 3
The check-in reservationist greets Guest 6
Assign room 1 to Guest 6
Guest 3 receives the total balance of $0
Guest 3 makes a payment
Guest 6 receives Room 1 and completes check-in
Guest 2 waits for check-out
Receive $58 from Guest 3 and complete the check-out
Guest 7 goes to the check-in reservationist
Guest 2 goes to the check-out reservationist and returns room 2
Guest 6: Go to hotel fitness center
The check-out greets Guest 2 and receives the key from room 2
Calculate the balance for Guest 2
Guest 0 waits for check-out
Guest 6 sleeps for 2 seconds
The check-in reservationist greets Guest 7
Guest 2 receives the total balance of $0
Guest 2 makes a payment
Assign room 2 to Guest 7
Receive $58 from Guest 2 and complete the check-out
Guest 7 receives Room 2 and completes check-in
Guest 7: Go to hotel fitness center
Guest 8 goes to the check-in reservationist
Guest 7 sleeps for 2 seconds
Guest 0 goes to the check-out reservationist and returns room 3
Guest 4 waits for check-out
The check-out greets Guest 0 and receives the key from room 3
Calculate the balance for Guest 0
Guest 0 receives the total balance of $58
Guest 0 makes a payment
Receive $58 from Guest 0 and complete the check-out
The check-in reservationist greets Guest 8
Assign room 3 to Guest 8
Guest 4 goes to the check-out reservationist and returns room 4
Guest 8 receives Room 3 and completes check-in
Guest 8: Go to hotel fitness center
Guest 9 goes to the check-in reservationist
Guest 8 sleeps for 2 seconds
The check-out greets Guest 4 and receives the key from room 4
Calculate the balance for Guest 4
The check-in reservationist greets Guest 9
Assign room 4 to Guest 9
Guest 4 receives the total balance of $0
Guest 4 makes a payment
Guest 9 receives Room 4 and completes check-in
Receive $58 from Guest 4 and complete the check-out
Guest 9: Go to hotel fitness center
Guest 9 sleeps for 2 seconds
Guest 5 waits for check-out
Guest 5 goes to the check-out reservationist and returns room 0
The check-out greets Guest 5 and receives the key from room 0
Calculate the balance for Guest 5
Guest 5 receives the total balance of $0
Guest 5 makes a payment
Receive $293 from Guest 5 and complete the check-out
Guest 6 waits for check-out
Guest 6 goes to the check-out reservationist and returns room 1
Guest 7 waits for check-out
The check-out greets Guest 6 and receives the key from room 1
Calculate the balance for Guest 6
Guest 6 receives the total balance of $0
Guest 6 makes a payment
Receive $293 from Guest 6 and complete the check-out
Guest 8 waits for check-out
Guest 7 goes to the check-out reservationist and returns room 2
Guest 9 waits for check-out
The check-out greets Guest 7 and receives the key from room 2
Calculate the balance for Guest 7
Guest 7 receives the total balance of $32604
Guest 7 makes a payment
Receive $293 from Guest 7 and complete the check-out
Guest 8 goes to the check-out reservationist and returns room 3
The check-out greets Guest 8 and receives the key from room 3
Calculate the balance for Guest 8
Guest 8 receives the total balance of $0
Guest 8 makes a payment
Receive $293 from Guest 8 and complete the check-out
Guest 9 goes to the check-out reservationist and returns room 4
The check-out greets Guest 9 and receives the key from room 4
Calculate the balance for Guest 9
Guest 9 receives the total balance of $0
Guest 9 makes a payment
Receive $293 from Guest 9 and complete the check-out
        BETWEEN THREAD JOINS 1
        BETWEEN THREAD JOINS 2
Segmentation fault (core dumped)
2
I just compiled and ran your program and I don't get a segfault. Do you get it every time? What is the version of gcc that you're using (gcc --version)?stanm
Also, it will help if you include your output in your question (including error).stanm
@stanm I do get the error every time I run it. The computer I compile/execute on returns "gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4 I have added the Output in my question.Tawm
It seems that there are race conditions taking place. The program sometimes crashes for me, sometimes it doesn't. Currently, it is stuck by both check-in and check-out waiting on semaphores (s1 and s3, resp), one guest waiting on s2, and three guests waiting on check_in.stanm
@stanm I am picking up on that as well, where sometimes I receive a SegFault, while others, it hangs forever after a "Guest completes check-out".Tawm

2 Answers

2
votes

The problem is line 71:

guest_data[guestid].event = gevent; // assign to Guest's struct

guest_data is already offset when being passed to the Guest function in main:

rc = pthread_create(&guests[guest], NULL, Guest, (void *)&thread_data_array[guest]); //Guest method, &thread_data_array[guest] argument

For this reason, line 71 should instead read:

guest_data->event = gevent; // assign to Guest's struct

or (not tested):

thread_data_array[guestid].event = gevent;

The segfault actually occurs in one of the threads, but unfortunately is manifested only during calls in pthread making it harder to localize and debug. Check out the discussion: https://chat.stackoverflow.com/rooms/110577/discussion-between-stanm-and-tawm

A question that might be related: C++ libpthread program segfaults for unknown reason

0
votes

valgrind aborts:

==8635== Process terminating with default action of signal 6 (SIGABRT)
==8635== at 0x508C418: raise (raise.c:54)
==8635== by 0x508E019: abort (abort.c:89)
==8635== by 0x50CE729: __libc_message (libc_fatal.c:175)
==8635== by 0x50CE74D: __libc_fatal (libc_fatal.c:185)
==8635== by 0x4E49C8D: futex_fatal_error (futex-internal.h:200)
==8635== by 0x4E49C8D: futex_wake (futex-internal.h:247)
==8635== by 0x4E49C8D: sem_post@@GLIBC_2.2.5 (sem_post.c:57)
==8635== by 0x400A16: Guest (in /home/oem/test99)
==8635== by 0x4E416F9: start_thread (pthread_create.c:333)

restarting with helgrind, reveals more problems (data used without locks, causes cache-problems), these there are many of

==8774== Possible data race during read of size 4 at 0x6020A0 by thread #5
==8774== Locks held: none
==8774== at 0x400CB4: RoomAvailable (in /home/oem/test99)
==8774== by 0x4009CD: Guest (in /home/oem/test99)
==8774== by 0x4C34DB6: ??? (in /usr/lib/valgrind/vgpreload_helgrind- amd64-linux.so)
==8774== by 0x4E476F9: start_thread (pthread_create.c:333)
==8774==
==8774== This conflicts with a previous write of size 4 by thread #2
==8774== Locks held: none
==8774== at 0x400C86: GetOpenRoom (in /home/oem/test99)
==8774== by 0x400D27: CheckIn (in /home/oem/test99)
==8774== by 0x4C34DB6: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==8774== by 0x4E476F9: start_thread (pthread_create.c:333)
==8774== Address 0x6020a0 is 0 bytes inside data symbol "rooms"