简体   繁体   中英

C - Segmentation fault using mutex and threads

I'm using threads and mutex with it. But for some reason, i can't figure out why, i get some segmentation faults. Can't use gdb because i cannot get that error =/

Also i tried to make some prints between lines but cannot see any relevant information...

Can someone tell my why is this happening ?

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

// Not order for easy random implementation
#define CITY_B 1
#define CITY_A 2
#define CITY_C 3
#define CITY_D 4
#define TRAIN_NUMBER 3

pthread_mutex_t lineAB;
pthread_mutex_t lineBC;
pthread_mutex_t lineBD;

typedef struct {
    int num;
    int from;
    int to;
}Train;

int generateRandom(int min, int max, int seed) {
    srand(time(NULL)+seed);
    return ((rand()%max)+min);
}

char * getCurrentTime() {
    char * timeString = (char *) malloc(sizeof(char) * 20);
    time_t now = time(NULL);
    strftime(timeString, 20, "%H:%M:%S", localtime(&now));
    return timeString;
}

char * hora() {
    return getCurrentTime();
}

pthread_mutex_t * nextLine(int from, int to) {
    switch(from) {
        case CITY_A: {
            return &lineAB;
        }
        case CITY_B: {
            switch(to) {
                case CITY_A: {
                    return &lineAB;
                }
                case CITY_C: {
                    return &lineBC;
                }
                case CITY_D: {
                    return &lineBD;
                }
            }
            break;
        }
        case CITY_C: {
            return &lineBC;
        }
        case CITY_D: {
            return &lineBD;
        }
    }
}

char * getCityName(int num) {
    switch(num) {
        case CITY_A: {
            return "City A";
        }
        case CITY_B: {
            return "City B";
        }
        case CITY_C: {
            return "City C";
        }
        case CITY_D: {
            return "City D";
        }
    }
}

char * getLineName(int from, int to) {
    switch(from) {
        case CITY_A: {
            return "cityA-cityB";
            break;
        }
        case CITY_B: {
            switch(to) {
                case CITY_A: {
                    return "cityA-cityB";
                    break;
                }
                case CITY_C: {
                    return "cityB-cityC";
                    break;
                }
                case CITY_D: {
                    return "cityB-cityD";
                    break;
                }
            }
            break;
        }
        case CITY_C: {
            return "cityB-cityC";
            break;
        }
        case CITY_D: {
            return "cityB-cityD";
            break;
        }
    }
}

void * threadFunc(void *arg){
    Train * train = (Train*)arg;
    /*int trainNum = info[0];
    int from = info[1];
    int to = info[2];*/
    char * partida = hora();
    char * chegada;

    printf("Train %d, From: %s, To: %s\n", train->num, getCityName(train->from), getCityName(train->to));

    //printf("A\n");
    pthread_mutex_t * myMutex = nextLine(train->from, CITY_B);
    pthread_mutex_lock(myMutex);
    //printf("B\n");
    printf("Train: %d\tLine: %s\tFrom: %s\tTo: %s\n", train->num, 
        getLineName(train->from, CITY_B), getCityName(train->from), getCityName(train->to));
    // Each line takes x sec to finish
    //printf("C\n");
    sleep(3);
    //printf("D\n");
    pthread_mutex_unlock(myMutex);
    //printf("E\n");
    myMutex = nextLine(CITY_B, train->to);
    //printf("F\n");
    printf("Train: %d\tLine: %s\tFrom: %s\tTo: %s\n", train->num, 
        getLineName(CITY_B, train->to), getCityName(train->from), getCityName(train->to));
    // Each line takes x sec to finish
    //printf("G\n");
    sleep(3);
    //printf("H\n");
    pthread_mutex_unlock(myMutex);
    //printf("I\n");
    chegada = hora();
    //printf("J\n");
    printf("\nTrain: %d\nDeparture: %s\tArrival: %s\n\n", train->num, partida, chegada);
    //printf("K\n");
    pthread_exit((void*)NULL);
}

int main(char *arg, char **args){
    pthread_t threads[TRAIN_NUMBER];
    Train trains[TRAIN_NUMBER];

    lineAB = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
    lineBC = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
    lineBD = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;

    srand(time(NULL));
    int i;
    for (i = 0; i < TRAIN_NUMBER; ++i) {
        trains[i].num = i+1;
        trains[i].from = generateRandom(CITY_A, CITY_D, i);
        if(trains[i].from == CITY_A) {
            trains[i].to = generateRandom(CITY_C, CITY_D, i);
        } else {
            trains[i].to = CITY_A;
        }
        pthread_create(&threads[i],NULL,threadFunc,(void*)&trains[i]);
    }

    for(i = 0; i < TRAIN_NUMBER; i++) {
        pthread_join(threads[i], NULL);
    }

    pthread_mutex_destroy(&lineAB);
    pthread_mutex_destroy(&lineBC);
    pthread_mutex_destroy(&lineBD);

    return 0;
}

Here are some results of the code !

Example 1 (Before printing anything):

make: *** [run] Segmentation fault

Example 2:

Train 1, From: City D, To: City A
Train: 1    Line: cityB-cityD   From: City D    To: City A
Train 3, From: City D, To: City A
make: *** [run] Segmentation fault

Example 3:

Train 1, From: City A, To: City C 
Train: 1    Line: cityA-cityB   From: City A    To: City C
Train 2, From: City A, To: City C
Train 3, From: City C, To: City A
Train: 3    Line: cityB-cityC   From: City C    To: City A
Train: 1    Line: cityB-cityC   From: City A    To: City C
Train: 3    Line: cityA-cityB   From: City C    To: City A
Train: 2    Line: cityA-cityB   From: City A    To: City C
Train: 2    Line: cityB-cityC   From: City A    To: City C

Train: 1 Departure: 18:51:55    Arrival: 18:52:01

Train: 3 Departure: 18:51:55    Arrival: 18:52:01

Train: 2 Departure: 18:51:55    Arrival: 18:52:04

I ran the program with

ulimit -c unlimited

this caused a core file to be generated. Now whe can run gdb.

Debugging this core file shows the error is at this line:

printf("Train %d, From: %s, To: %s\n", train->num, getCityName(train->from), getCityName(train->to));

Printing train gives:

(gdb) print *train

$3 = {num = 3, from = 5, to = 2}

So train->from is invalid (valid is 1-4)!

train->to and train->from is generated with generateRandom(), so the bug must be here.

int generateRandom(int min, int max, int seed) {
    srand(time(NULL)+seed);
    return ((rand()%max)+min);
}

rand()%max can generate number from 0 to max-1. Adding min to this can give max+min-1. Since inputs are 2 (CITY_A) and 4 (CITY_D) you can get numbers between 2 and 5. You probably want this instead:

int generateRandom(int min, int max, int seed) {
    srand(time(NULL)+seed);
    return ((rand()%(max-min))+min);
}

the posted code contains LOTS of problems, most of which are indicated in the comments.

However, the main problem is in the generateRandom() function at this line:

return ((rand()%max)+min);

which is generating values that are greater than 3 (5 being typical)

Then, later in the code, the access to the mutex array is accessing beyond the end of the array.

Then the call to pthread_mutex_lock() is being fed an invalid pointer, resulting in the seg fault event.

Two passes with the gdb debugger along with some 'useful' calls to printf() quickly located the source of the problem.

Strongly suggest you become very familiar with a debugger.

here is the version of the code that I used for debugging:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h> // rand(), srand()
#include <unistd.h>

// Not order for easy random implementation
#define CITY_B 1
#define CITY_A 2
#define CITY_C 3
#define CITY_D 4
#define TRAIN_NUMBER 3

pthread_mutex_t lineAB = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lineBC = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lineBD = PTHREAD_MUTEX_INITIALIZER;

struct TrainStruct
{
    size_t num;
    size_t from;
    size_t to;
};

typedef struct TrainStruct Train;


size_t generateRandom(int min, int max, size_t seed)
{
    (void)seed;
    //srand(time(NULL)+seed);
    return (size_t)((rand()%max)+min);
}


char * getCurrentTime()
{
    char * timeString = malloc(20);
    time_t now = time(NULL);
    strftime(timeString, 20, "%H:%M:%S", localtime(&now));
    return timeString;
} // end function: getCurrentTime


char * hora() {
    return getCurrentTime();
}

pthread_mutex_t * nextLine(size_t from, size_t to)
{
    switch(from)
    {
        case CITY_A:
            return &lineAB;
            break;

        case CITY_B:
            switch(to)
            {
                case CITY_A:
                    return &lineAB;
                    break;

                case CITY_C:
                    return &lineBC;
                    break;

                case CITY_D:
                    return &lineBD;
                    break;

                default:
                    printf( "invalid  train.to: %lu\n", to);
                    return NULL;
                    break;
            } // end switch
            break;

        case CITY_C:
            return &lineBC;
            break;

        case CITY_D:
            return &lineBD;
            break;

        default:
            printf( "invalid  train.from: %lu\n", from);
            return NULL;
            break;
    } // end switch
}


char * getCityName(size_t num)
{
    switch(num)
    {
        case CITY_A:
            return "City A";
            break;

        case CITY_B:
            return "City B";
            break;

        case CITY_C:
            return "City C";
            break;

        case CITY_D:
            return "City D";
            break;

        default:
            printf( "invalid  city num: %lu\n", num);
            return NULL;
            break;
    } // end switch
}


char * getLineName( size_t from, size_t to)
{
    switch(from)
    {
        case CITY_A:
            return "cityA-cityB";
            break;

        case CITY_B:
            switch(to)
            {
                case CITY_A: {
                    return "cityA-cityB";
                    break;
                }
                case CITY_C:
                    return "cityB-cityC";
                    break;

                case CITY_D:
                    return "cityB-cityD";
                    break;

                default:
                    printf( "invalid  train.to: %lu\n", to);
                    return NULL;
                    break;
            } // end switch
            break;

        case CITY_C:
            return "cityB-cityC";
            break;

        case CITY_D:
            return "cityB-cityD";
            break;

        default:
            printf( "invalid  train.from: %lu\n", from);
            return NULL;
            break;
    } // end switch
}


void * threadFunc(void *arg)
{
    Train * train = (Train*)arg;
    /*int trainNum = info[0];
    int from = info[1];
    int to = info[2];*/
    char * partida = hora();
    char * chegada;

    // for testing
    printf( "func:%s\n num: %lu\n from: %lu\n to: %lu\n\n",
            __func__,
            train->num,
            train->from,
            train->to);

    printf("Train %lu, From: %s, To: %s\n\n",
        train->num,
        getCityName(train->from),
        getCityName(train->to));

    //printf("A\n");
    pthread_mutex_t * myMutex = nextLine(train->from, CITY_B);
    pthread_mutex_lock(myMutex);
    //printf("B\n");
    printf("Train: %lu\tLine: %s\tFrom: %s\tTo: %s\n",
        train->num,
        getLineName(train->from, CITY_B),
        getCityName(train->from),
        getCityName(train->to));

    // Each line takes x sec to finish
    //printf("C\n");
    sleep(3);
    //printf("D\n");
    pthread_mutex_unlock(myMutex);


    //printf("E\n");
    myMutex = nextLine(CITY_B, train->to);
    //printf("F\n");
    printf("Train: %lu\tLine: %s\tFrom: %s\tTo: %s\n",
        train->num,
        getLineName(CITY_B, train->to),
        getCityName(train->from),
        getCityName(train->to));

    // Each line takes x sec to finish
    //printf("G\n");
    sleep(3);
    //printf("H\n");
    pthread_mutex_unlock(myMutex);


    //printf("I\n");
    chegada = hora();
    //printf("J\n");
    printf("\nTrain: %lu\nDeparture: %s\tArrival: %s\n\n",
        train->num,
        partida,
        chegada);
    //printf("K\n");
    pthread_exit((void*)NULL);
}

int main( void )
{
    pthread_t threads[TRAIN_NUMBER];
    Train trains[TRAIN_NUMBER];



    srand((unsigned)time(NULL));

    for (size_t i = 0; i < TRAIN_NUMBER; ++i)
    {
        trains[i].num = i+1;
        trains[i].from = generateRandom(CITY_A, CITY_D, i);

        if(trains[i].from == CITY_A)
        {
            trains[i].to = generateRandom(CITY_C, CITY_D, i);
        }

        else
        {
            trains[i].to = CITY_A;
        }

        pthread_create(&threads[i],NULL,threadFunc,(void*)&trains[i]);
    }

    for(size_t i = 0; i < TRAIN_NUMBER; i++)
    {
        pthread_join(threads[i], NULL);
    }

    pthread_mutex_destroy(&lineAB);
    pthread_mutex_destroy(&lineBC);
    pthread_mutex_destroy(&lineBD);
} // end function: main

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM