我正在尝试创建一个将对具有多个线程的数组进行排序的C代码,因此我需要使用屏障来同步威胁
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);
}
我的论点结构看起来像这样
struct ThreadArguments {
unsigned int id;
int* array;
pthread_barrier_t* barrier;
}
这就是我初始化障碍的方式
pthread_barrier_init (&barrier, NULL, 4);
我希望它做一次迭代的排序方法,然后等待所有线程在障碍处完成然后继续进行,但是这样做是
thread 0 started
thread 1 started
thread 2 started
thread 3 started
然后卡住。可能是什么问题?
编辑:完整代码
#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;
}
最佳答案
障碍
pthread_barrier_t enter_barrier; //this barrier synchornizes threads to wait
是函数
initializeThreads()
中的本地对象。当initializeThreads()
完成时(在线程启动并调用pthread_barrier_wait (the_args->enter_barrier)
之前),该对象的生存期结束。难怪在一个不存在的障碍上等待是行不通的。关于c - C中的Pthread屏障,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34387051/