简体   繁体   中英

Pthread-Barriers in C

I am trying to create ac code that will sort an array with multiple threads, so i need to use barriers to synchronize threats

  void sort(struct ThreadArguments* args){
      struct ThreadArguments* the_args= (struct ThreadArguments*)args;
      printf("thread %d started \n", the_args->id);
      fflush(stdout);
      pthread_barrier_wait (the_args->barrier);
      printf("thread %d finished the iteration \n", the_args->id);
      fflush(stdout);
}

My arguments structure looks like that

struct ThreadArguments {
 unsigned int id; 
 int* array;
 pthread_barrier_t* barrier;
}

And this is how I initialize barriers

pthread_barrier_init (&barrier, NULL, 4);

I expect it to do one iteration of sorting method then wait for all threads finish at the barrier then proceed, but what is does is

thread 0 started 
thread 1 started 
thread 2 started 
thread 3 started 

and then get stuck. What might be the problem? EDIT: Full code

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <string.h>
#include <pthread.h>

#define MAXFILENAME 64
#define TIMESTEP 200000
#define MAXTHREADS 2046





//Thread arguemnt struct
struct ThreadData {
    unsigned int id; //thread's id
    int start;   //starting index of the workers's part
    int step;   //step between each consecutive cells
    int cells;   //how many cells is worker respnsible for
    pthread_barrier_t* enter_barrier; //this barrier synchornizes threads to wait till the copy of the array is created
    pthread_barrier_t* exit_barrier;  //this barrier is used to wait till all threads finished updating
    pthread_barrier_t* print_barrier;
    int print;
    int iter;
    int rows;   //row dimensions
    int columns;  //column dimensions
    char* array;  //pointer to the original array
    char* working_array; //pointer to the dublicate array used during each step
};



int readIn(int *rows, int *columns, int *iter, int *num_cells, FILE *fp);
char *initialize(int rows, int columns, int num_cells, FILE *fp);
void printBoard(int rows, int columns, char *cells, int num_cells);
int checkNeighb(int rows, int columns, char *cells, int num_cells, int target);
void evolve(struct ThreadData* args);
void printUsage(int code);
void initializeThreads(int part_type, int num_iter, int print_opt, struct ThreadData* data, int num_threads, int num_rows, int num_cols, char* cells);
int processAgrs(int argc, char **argv, char **filename, int* print_opt, int* num_threads, int* part_type, int* print_per_thread);



// Main method
int main(int argc, char *argv[]) {

    int num_rows;  //number of rows on the board
    int num_cols;
    int num_iter;
    int num_cells;
    int print_opt;
    int num_threads;
    int part_type;
    int print_per_thread;
    int i, ret;

    char *filename = malloc(MAXFILENAME*sizeof(char));
    ret = processAgrs(argc, argv, &filename, &print_opt, &num_threads, &part_type, &print_per_thread);
    if(ret == -1)
    {
        exit(1);
    }

    FILE *fp = fopen (filename, "rb");        //openning file

    if(fp == NULL)
    {
        perror("Error openning file");
        exit(1);
    }

    if(readIn(&num_rows, &num_cols, &num_iter, &num_cells, fp) == -1)   //check that everything was successful
    {
        printf("Error reading from file \n");
        exit(1);
    }

    char* cells  = initialize(num_rows, num_cols, num_cells, fp);
    if(cells == NULL)
    {
        printf("Error initializing board! \n");
        exit(1);
    }
    struct ThreadData *data = malloc(num_threads * sizeof(struct ThreadData));
    initializeThreads(part_type, num_iter, print_opt,  data, num_threads, num_rows, num_cols, cells);
    struct timeval start_time, end_time;
    double elapsed = 0;

    if(gettimeofday(&start_time, NULL) == -1)
    {
        printf("Error getting time \n");
        elapsed = -1;
    }

    pthread_t *thread = malloc(num_threads*sizeof(pthread_t));
    printf("Start creating threads");
    fflush(stdout);
    // Launching Threads
    for (i=0; i<num_threads; i++) {
        printf("Create threads %d \n", i);
        fflush(stdout);
        ret = pthread_create(&thread[i], NULL,(void *) &evolve,(void *) &data[i]);
        if(ret != 0)
        {
            printf("Error creating thread");
        }
    }

    // Waiting for Threads to Finish
    for (i=0; i<num_threads; i++) {
        pthread_join(thread[i], NULL);
    }

    if(gettimeofday(&end_time, NULL) == -1 || elapsed == -1)
    {
        printf("Time was not calulcated due to error! \n");
    }
    else{  //print ellapsed time
        elapsed = (end_time.tv_sec - start_time.tv_sec) + (end_time.tv_usec - start_time.tv_usec) / 1000000.0;
        printf("total time for %d iterations of %dx%d world is %.6f secs \n",num_iter, num_rows, num_cols, elapsed);
    }

    free(cells);
    free(filename);
    return 0;
}

void initializeThreads(int part_type, int num_iter, int print_opt, struct ThreadData* data, int num_threads, int num_rows, int num_cols, char* cells)
{
    int i, prev;
    int num_of_extras; //extras is thread that gets one more line/column
    pthread_barrier_t enter_barrier; //this barrier synchornizes threads to wait
    //till the copy of the array is created
    pthread_barrier_t exit_barrier;//this barrier waits for all threads to finish updating cells
    pthread_barrier_t print_barrier;


    pthread_barrier_init (&enter_barrier, NULL, num_threads);  //initialize barrier for copying array
    pthread_barrier_init (&exit_barrier, NULL, num_threads);   //initialize exit barrier
    pthread_barrier_init (&print_barrier, NULL, num_threads);

    char *copy_cells = malloc((num_rows * num_cols) * sizeof(char));
        if(copy_cells == NULL)      //Checking malloc
         {
                 perror("Error mallocing");
                 free(copy_cells);
                 return;
         }

    for (i = 0; i < num_threads; i++)
{
    data[i].enter_barrier = &enter_barrier;
    data[i].exit_barrier = &exit_barrier;
    data[i].print_barrier = &print_barrier;
    data[i].iter = num_iter;
    data[i].rows = num_rows;
    data[i].columns = num_cols;
    data[i].working_array = copy_cells;
    data[i].array = cells;
    data[i].print = print_opt;
}       
    if( part_type == 0)    //if row-wise paritioning
    {

        int lines_per_thread = num_rows / num_threads;
        num_of_extras = num_rows % num_threads;
        prev = 0;
        for (i = 0; i < num_threads; i++)
        {
            data[i].id = i;
            data[i].start = prev;
            if( num_of_extras == 0)
            {
                data[i].cells = lines_per_thread * num_cols;
                prev+=data[i].cells;
            }
            else{

                data[i].cells = (lines_per_thread + 1) * num_cols;
                prev+=data[i].cells;
                        num_of_extras--;
            }
        data[i].step = 1;
        }
    }
    else{     //column-wise patitioning
        int columns_per_thread = num_cols / num_threads;
        num_of_extras = num_cols % num_threads;
        prev = 0;
        for (i = 0; i < num_threads; i++)
        {
            data[i].id = i;
            data[i].start = prev;
            if( num_of_extras == 0)
            {
                data[i].cells = columns_per_thread * num_rows;
            }
            else{
                data[i].cells = (columns_per_thread + 1) * num_rows;
                num_of_extras--;
            }
            data[i].step = num_cols;
            prev++;
        }
    }

}



int processAgrs(int argc, char **argv, char **filename, int* print_opt, int* num_threads, int* part_type, int* print_per_thread)
{
    if (argc < 6) {      //reading arguments from command line
        printf("Too few arguments!");
        printUsage(1);
        return -1;
    }
    else if(argc > 6)
    {
        printf("Too many arguments!");
        printUsage(1);
        return -1;
    }
    else
    {
        strcpy(*filename, argv[1]);


        *print_opt = strtol(argv[2], NULL, 10);    //using strtol() to convert string to int
        if(*print_opt < 0 || *print_opt > 1)
        {
            printf("Illiegal prinitng option! \n 1 - Print \n 0 - Don't print \n");
            printUsage(1);
            return -1;
        }



        *num_threads = strtol(argv[3], NULL, 10);    //using strtol() to convert string to int
        if(*num_threads < 1 || *num_threads > MAXTHREADS)
        {
            if( *num_threads == -1)
            {
                printf("Having %d thread is not allowed! \n",*num_threads);  //for correct grammar print "thread" if user entered -1
            }
            else{
                printf("Having %d threads is not allowed! \n",*num_threads);
            }
            return -1;
        }



        *part_type = strtol(argv[4], NULL, 10);    //using strtol() to convert string to int
        if(*part_type < 0 || *part_type > 1)
        {
            printf("Illiegal partitioning option! \n");
            printUsage(2);
            return -1;
        }




        *print_per_thread = strtol(argv[5], NULL, 10);    //using strtol() to convert string to int
        if(*print_per_thread < 0 || *print_per_thread > 1)
        {
            printf("Illiegal prinitng option! \n 1 - Print \n 0 - Don't print \n");
            printUsage(1);
            return -1;
        }

        return 0;
    }
}
/* @biref this method prints usage infromation for a specified case
 * @arg code ths arguemnts sepcifies which help message should be printed, general usage is argument 0
 */
void printUsage(int code)
{
    switch( code )
    {
        case 0:
            printf("Usage: \n");
            printf("    ./gol   print-option    number of threads    partitioning-type      print-per-thread\n");
            printf(" Example: \n");
            printf("    ./gol file1.txt  0  8  0  1 \n");
            printf("    run with config values read from file1.txt, do not print the board after\n each round, create 8 threads, use row-wise partitioning, print per-thread\npartitioning details");
            break;
        case 1:
            printf("Print options are 1 or 0.\n");
            printf("    1 for print \n  0 for do not print");
            break;
        case 2:
            printf("Partitioning orptions are 1 or 0.\n");
            printf("    0 for row-wise partitioning \n  1 for column-wise partitioning");
            break;
        default :
            break;
    }
}




/* @biref this method does one step of the game by first calling checkNeighb() and then choosing apporopriate action
 * @param rows - number of rows of the field
 * @param columns - number of comuns of the filed
 * @param cells - pointer to the 1D array representing our field
 * @param num_cells - total number of cells
 */
void evolve(struct ThreadData* args)
{
    //////////////

    struct ThreadData* the_args= (struct ThreadData*)args;
    printf("thread %d started", the_args->id);
    fflush(stdout);

/*  int i;
    int neighb;
    int start = the_args->start;
    int step = the_args->step;
    int num_cells = the_args->cells;
    int end;
    int total_cells = (the_args->columns * the_args->rows);

if(the_args->id == 0)  //print the initial state of the board
    {   system("clear");
        if(the_args->print == 1)
        {
            printf("Time step: %d \n\n", TIMESTEP);
            printBoard(the_args->rows, the_args->columns , the_args->array, total_cells);
            usleep(TIMESTEP);
        }
    }

    ///Main loop. Each itteration of the loop is a one round of game.
    for(i = 0; i < the_args->iter; i++)
    {
        //DEBUG
        end = (start + (num_cells * step));
        for(i = start; i < end ; i+=step)   //copy cell  state to the array
        {
            the_args->working_array[i] = the_args->array[i];
        }
        //barrier
        printf("at the barrier, %d!", the_args->id);
                fflush(stdout);
*/
        pthread_barrier_wait (the_args->enter_barrier);
/*
        for(i = start; i < end; i+=step)
        {
            neighb = checkNeighb(the_args->rows, the_args->columns, the_args->array, num_cells,  i);   //get number of neighbors
            if((neighb < 2 || neighb > 3) && the_args->array[i] == 1)
            {
                the_args->working_array[i] = 0;
            }else if( the_args->array[i] == 0 && neighb == 3)
            {
                the_args->working_array[i] = 1;
            }
        }


        //barrier
        pthread_barrier_wait (the_args->exit_barrier);
        for(i = start; i < end; i+=step)
        {
            the_args->array[i] = the_args->working_array[i];
        }
        //barrier
        pthread_barrier_wait (the_args->print_barrier);
        if(the_args->id == 0)  //first (0th) thread should print the board
        {   system("clear");
            printf("at the second print \n");
            if(the_args->print == 1)
            {
                printf("Time step: %d \n\n", TIMESTEP);
                printBoard(the_args->rows, the_args->columns , the_args->array, total_cells);
                usleep(TIMESTEP);
            }
        }

    }
*/
}
/*
 * @biref this read in main parameters from text file
 * @param num_rows - pointer to the number of rows of the field
 * @param num_columns - pointer to the number of comuns of the filed
 * @param num_iter - pointer to the number of iterations
 * @param num_cells - pointer to the total number of cells
 * @param fp - pointer to the open file
 * @return returns 0 on success and -1 on error
 */
int readIn(int *num_rows, int *num_columns, int *num_iter, int *num_cells, FILE *fp)
{

    if(fscanf(fp, "%d", num_rows) < 1)
        return -1;

    if(fscanf(fp, "%d", num_columns) < 1)
        return -1;

    if(fscanf(fp, "%d", num_iter) < 1)
        return -1;

    if(fscanf(fp, "%d", num_cells) < 1 )
        return -1;


    return 0;
}

/* @biref this method creates a 1D array and fills it with the corrct data
 * @param rows - number of rows of the field
 * @param columns - number of comuns of the filed
 * @param - which way should the array be asigned by columns or by rows (used to optimize perfomance in a column partitioning)
 * @param num_cells - total number of cells
 * @param fp - pointer to the open file
 * @return - returns pointer to the 1D array
 */
char* initialize(int rows, int columns, int num_cells, FILE *fp)
{
    int k = 0;
    int i, j, index;
    int length = (rows * columns); //total number of elements in the array (area of the board)
    char *cells = calloc((rows * columns), sizeof(char));
    if(cells == NULL)    //checking malloc
    {
        perror("Error mallocing");
        free(cells);
        return NULL;
    }

    while( k < num_cells )
    {
        if(fscanf(fp, "%d %d",&i ,&j) == 2)
        {
            index = ((i * columns) + j);
            if(index < length)
            {
                cells[index] = 1;
            }
            else{      //in case entries are outside of the board
                printf("Invalid entry: %d %d is outside the boundaries", i, j);
            }
            k++;
        }
        else{
            printf("Error reading i j coordinate pair %d", k);
        }
    }
    return cells;
}

/*
 * @biref this method counts number of naeighbors of the cell with a given index in a 1D representation
 * @param rows - the number of rows of the field
 * @param columns - the number of comuns of the filed
 * @param cells - pointer to the 1D arrray
 * @param num_cells - the total number of cells
 * @param target - index of the cell
 * @return returns number of neighbors
 */
int checkNeighb(int rows, int columns, char *cells, int num_cells, int target)
{
    int count = 0;

    if((target % columns) == 0)  //left edge
    {
        if( target == 0 )    //top left corner
        {
            if( cells[(rows*columns) -1 ] == 1) //up-left 1
            {
                count++;
            }
            if( cells[((rows -  1) * columns)]  == 1) //up 2
            {
                count ++;
            }
            if( cells[((rows -  1) * columns)+ 1] == 1)  //up-right 3
            {
                count ++;
            }

        }
        else{ //if not top left corner
            if( cells[target - 1] == 1) //up-left 1.1
            {
                count++;
            }
            if( cells[(target - columns)] == 1) //up 2.1
            {
                count ++;
            }
            if( cells[(target - columns) + 1]  == 1)  //up-right 3.1
            {
                count++;
            }
        }

        if( target == (rows - 1) * columns)  //bottom left corner
        {
            if( cells[(columns)-1 ] == 1) //down-left 4
            {
                count++;
            }
            if( cells[0] == 1) //down 5
            {
                count ++;
            }
            if( cells[1] == 1)  //up-right 6
            {
                count ++;
            }
        }
        else{
            //if not bottom left corner
            if( cells[ target + (2 * columns) - 1 ] == 1) //down-left 4.1
            {
                count++;
            }
            if( cells[ target + columns ] == 1) //down 5.1
            {
                count ++;
            }
            if( cells[ (target + columns) + 1] == 1)  //down-right 6.1
            {
                count ++;
            }
        }


        if( cells[ target + 1] == 1) //right 7
        {
            count++;
        }
        if(cells[(target + columns) - 1] == 1)  //left 8
        {
            count++;
        }
    }
    else if(((target +1) % columns) == 0)  //right edge
    {

        if( target == (columns - 1) )    //top right corner
        {
            if( cells[(rows * columns) - 2 ] == 1) //up-left 1
            {
                count++;
            }
            if( cells[(rows * columns) - 1]  == 1) //up 2
            {
                count ++;
            }
            if( cells[((rows-1) * columns)]  == 1)  //up-right 3
            {
                count ++;
            }

        }
        else{ //if not top right corner
            if( cells[(target - columns) - 1] == 1) //up-left 1.1
            {
                count++;
            }
            if( cells[(target - columns)] == 1) //up 2.1
            {
                count ++;
            }
            if( cells[(target - (2 * columns)) + 1] == 1)  //up-right 3.1
            {
                count++;
            }
        }

        if( target == ((rows * columns) -1))  //bottom right corner
        {
            if( cells[columns - 2 ] == 1) //down-left 4
            {
                count++;
            }
            if( cells[ columns - 1 ] == 1) //down 5
            {
                count ++;
            }
            if( cells[0] == 1)  //down-right 6
            {
                count ++;
            }
        }
        else{
            //if not bottom right corner
            if( cells[ (target + columns) - 1 ] == 1) //down-left 4.1
            {
                count++;
            }
            if( cells[ target + columns ] == 1) //down 5.1
            {
                count ++;
            }
            if( cells[ target + 1 ] == 1)  //down-right 6.1
            {
                count ++;
            }
        }
        if( cells[(target - columns) + 1] == 1)  //right 7
        {
            count++;
        }
        if(cells[target - 1 ] == 1)  //left 8
        {
            count++;
        }
    }
    else if(target > ((rows-1)*columns))  //bottom edge not corner
    {
        if(cells[target - 1] == 1)  //left 1
        {
            count++;
        }
        if(cells[target + 1] == 1)  //right 2
        {
            count++;
        }
        if(cells[target - columns] == 1)  //up 3
        {
            count++;
        }
        if(cells[(target - columns) - 1] == 1)  //up -left 4
        {
            count++;
        }
        if(cells[(target - columns) + 1] == 1)  //up -right 5
        {
            count++;
        }
        if(cells[target % columns] == 1)  //down 5
        {
            count++;
        }
        if(cells[(target % columns) + 1] == 1)  //down -right 7
        {
            count++;
        }
        if(cells[(target % columns) + -1] == 1)  //down -left 8
        {
            count++;
        }

    }
    else if(target < columns) //top edge not corners
    {
        if(cells[target - 1] == 1)  //left 1
        {
            count++;
        }
        if(cells[target + 1] == 1)  //right 2
        {
            count++;
        }

        if(cells[target + ((rows-1) * columns)] == 1)  //up 3
        {
            count++;
        }
        if(cells[(target + ((rows-1) * columns)) - 1] == 1)  //up -left 4
        {
            count++;
        }
        if(cells[(target + ((rows-1) * columns)) + 1] == 1)  //up - right 5
        {
            count++;
        }
        if(cells[target + columns] == 1)  //down 5
        {
            count++;
        }
        if(cells[(target + columns) + 1] == 1)  //down -right 7
        {
            count++;
        }
        if(cells[(target + columns) + -1] == 1)  //down -left 8
        {
            count++;
        }

    }
    else{ //middle


        if(cells[target - 1] == 1)  //left 1
        {
            count++;
        }
        if(cells[target + 1] == 1)  //right 2
        {
            count++;
        }

        if(cells[target - columns] == 1)  //up 3
        {

            count++;
        }
        if(cells[(target - columns) - 1] == 1)  //up -left 4
        {
            count++;
        }
        if(cells[(target - columns) + 1] == 1)  //up -right 5
        {
            count++;
        }
        if(cells[target + columns] == 1)  //down 5
        {
            count++;
        }
        if(cells[(target + columns) + 1] == 1)  //down -right 7
        {
            count++;
        }
        if(cells[(target + columns) + -1] == 1)  //down -left 8
        {
            count++;
        }
    }
    return count;
}

// @biref this method prints out the board
void printBoard(int rows, int columns, char *cells, int num_cells)
{
    int i, j;

    for( i = 0; i < rows; i++)
    {    
        for( j=0; j < columns; j++)
        {
            if( cells[ (i * columns) + j ] == 1)
            {
                printf("@ ");  //if 1
            }
            else{
                printf("- ");  //if 0
            }
        }
        printf("\n");
    }
    printf("\n");
    return;
}

The barrier

    pthread_barrier_t enter_barrier; //this barrier synchornizes threads to wait

is a local object in the function initializeThreads() . The lifetime of this object ends when initializeThreads() finishes, which is before the threads start and call pthread_barrier_wait (the_args->enter_barrier) . It's no wonder that waiting on a non-existent barrier doesn't work.

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