为什么我在 proj4.c 的第 18 行遇到分段错误?

问题描述 投票:0回答:0

所以我正在尝试创建一个程序,该程序使用多线程来查找从输入文本文件创建的网格的对角线和有多少与传递给程序的给定数字相匹配。

我像这样编译 proj4.c 和 main.c,以便在 unix 环境中使用提供的 make 文件访问 main.c 中的主要方法:

编译: gcc -Wall -pedantic-errors proj4.c -g -c -pthread gcc -Wall -pedantic-errors main.c -g -c gcc -Wall -pedantic-errors main.o proj4.o -g -o proj4.out -pthread

运行: ./proj4.out in1.txt out1.txt 10 1

清洁: rm *.out rm *.o

我在以下代码的第 18 行不断收到分段错误:

proj4.c:

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

// Function to read the grid from the input file
void initializeGrid(grid *g, char *fileName) {
    FILE *file = fopen(fileName, "r");
    if (!file) {
        perror("Error opening file");
        exit(EXIT_FAILURE);
    }

    fscanf(file, "%u", &g->n);

    g->p = (unsigned char **)malloc(g->n * sizeof(unsigned char *));
    for (unsigned int i = 0; i < g->n; i++) {
        g->p[i] = (unsigned char *)malloc(g->n * sizeof(unsigned char));
        for (unsigned int j = 0; j < g->n; j++) {
            fscanf(file, " %c", &g->p[i][j]);
        }
    }

    fclose(file);
}

// Define a struct to pass data to the worker function
typedef struct {
    grid *input;
    unsigned long s;
    grid *output;
    int thread_id;
    int total_threads;
} worker_args;

// Worker thread function
void *worker(void *args) {
    worker_args *w_args = (worker_args *)args;
    grid *input = w_args->input;
    unsigned long s = w_args->s;
    grid *output = w_args->output;
    int thread_id = w_args->thread_id;
    int total_threads = w_args->total_threads;

    unsigned int n = input->n;

    // Calculate the range of elements each thread should work on
    unsigned int work_size = (n * (n - 1)) / (2 * total_threads);
    unsigned int start = thread_id * work_size;
    unsigned int end = (thread_id + 1) * work_size;

    if (thread_id == total_threads - 1) {
        end = n * (n - 1) / 2;
    }

    for (unsigned int idx = start; idx < end; idx++) {
        int row, col;

        // Find row value without using sqrt
        row = n - 2;
        while (idx <= (row * (row + 1)) / 2) {
            row--;
        }

        col = idx - (row * (row + 1)) / 2;

        output->p[row][col] = (input->p[row][col] + input->p[col][row + 1]) % s;
    }

    return NULL;
}
// Function to find the diagonal sums
void diagonalSums(grid *input, unsigned long s, grid *output, int t) {
    pthread_t *threads = (pthread_t *)malloc(t * sizeof(pthread_t));
    worker_args *thread_args = (worker_args *)malloc(t * sizeof(worker_args));

    for (int i = 0; i < t; i++) {
        thread_args[i].input = input;
        thread_args[i].s = s;
        thread_args[i].output = output;
        thread_args[i].thread_id = i;
        thread_args[i].total_threads = t;

        if (pthread_create(&threads[i], NULL, worker, (void *)&thread_args[i]) != 0) {
            perror("Error creating thread");
            exit(EXIT_FAILURE);
        }
    }

    for (int i = 0; i < t; i++) {
        if (pthread_join(threads[i], NULL) != 0) {
            perror("Error joining thread");
            exit(EXIT_FAILURE);
        }
    }

    free(threads);
    free(thread_args);
}

// Function to write the grid to the output file
void writeGrid(grid *g, char *fileName) {
    FILE *file = fopen(fileName, "w");
    if (!file) {
        perror("Error opening file");
        exit(EXIT_FAILURE);
    }

    for (unsigned int i = 0; i < g->n; i++) {
        for (unsigned int j = 0; j < g->n; j++) {
            fprintf(file, "%c ", g->p[i][j]);
        }
        fprintf(file, "\n");
    }

    fclose(file);
}

// Function to free the grid
void freeGrid(grid *g) {
    for (unsigned int i = 0; i < g->n; i++) {
        free(g->p[i]);
    }
    free(g->p);
}

main.c:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>
#include <sys/time.h>
#include "proj4.h"

/*
 * Do not modify anything in this file. 
 */

/*
 * Helper function for main. 
 * Check for some errors and print error messages 
 * for command line arguments passed to main.
 * If an error is found, the program terminates.
 */
void errorCheck(int argc, char ** argv){
  bool errorFound = false;
  if(argc != 5){
    printf("Usage error: ./proj4.out inputFile outputFile s t\n");
    errorFound = true;
  }
  else if( access(argv[1], F_OK) != 0 ){
    printf("Error accessing %s in the present working directory\n", argv[1]);
    errorFound = true;
  }
  else {
    int t = atoi(argv[4]);
    if(t < 1 || 3 < t){
      printf("Error: t must be between 1 and 3 (inclusive)\n");
      errorFound = true;
    }
  }
  if(errorFound) exit(0);
}

/*
 * This program should be compiled to ./proj4.out using the provided
 * Makefile, and it will process five command line arguments.
 *   ./proj.out input.txt output.txt s t
 *      input.txt is the name of a file in the present working directory that 
 *        contains a n-by-n grid of digits (1 through 9),
 *        where n >= 1.
 *      output.txt is the name of a file in the present working directory to save
 *        the output of all of the diagonal sums. If the file does not exist,
 *        then this file will be created in the present working directory.
 *      s is the sum for the diagonal sums.
 *      t is the number of threads (1 <= t <= 3) to use
 *        to compute the diagonal sums. If t is 1, then only the 
 *        main thread will be used. If 2 <= t <= 3, then the main
 *        thread and (t - 1) POSIX thread(s) will be used to compute
 *        the diagonal sums.
 * This program will only time the call to diagonalSums.
 *
 */
int main(int argc, char ** argv){
  errorCheck(argc, argv);
  char * inputFile = argv[1];
  char * outputFile = argv[2];
  unsigned long sum = (unsigned long) atol(argv[3]);
  int t = atoi(argv[4]);
  grid g, diagonalSumsOutput;
  initializeGrid(&g, inputFile);

  printf("Computing the diagonal sums equal to %ld in a %d-by-%d grid using %d thread(s).\n",
         sum, g.n, g.n, t);
  struct timeval start, end;    // start and end time
  unsigned long e_usec; // elapsed microseconds
  gettimeofday(&start, 0); // mark the start time
  diagonalSums(&g, sum, &diagonalSumsOutput, t);
  gettimeofday(&end, 0);        // mark the end time
  e_usec = ((end.tv_sec * 1000000) + end.tv_usec) -
    ((start.tv_sec * 1000000) + start.tv_usec);
  printf("Elapsed time for computing the diagonal sums using %d thread(s): %lf seconds.\n",
         t, e_usec / 1000000.0);

  printf("Writing the diagonal sums equal to %ld to the file %s.\n",
         sum, outputFile);
  writeGrid(&diagonalSumsOutput, outputFile);
  freeGrid(&g);
  freeGrid(&diagonalSumsOutput);
  printf("Program is complete. Goodbye!\n");
  return 0;
}

proj4.h:

#ifndef PROJ4_H
#define PROJ4_H

/*
 * The struct grid_t contains a pointer p to a 2D array of 
 * unsigned chars with n rows and n columns stored on
 * the heap of this process. Once this is initialized properly,
 * p[i][j] should be a valid unsigned char for all i = 0..(n-1)
 * and j = 0..(n-1).
 * Do not alter this typedef or struct in any way.
 */
typedef struct grid_t {
  unsigned int n;
  unsigned char ** p;
} grid;


/*
 * Initialize g based on fileName, where fileName
 * is a name of file in the present working directory
 * that contains a valid n-by-n grid of digits, where each
 * digit in the grid is between 1 and 9 (inclusive).
 * Do not alter this function prototype in any way.
 */
void initializeGrid(grid * g, char * fileName);


/*
 * This function will compute all diagonal sums in input that equal s using
 * t threads, where 1 <= t <= 3, and store all of the resulting
 * diagonal sums in output. Each thread should do
 * roughly (doesn't have to be exactly) (100 / t) percent of the 
 * computations involved in calculating the diagonal sums. 
 * This function should call (or call another one of your functions that calls)
 * pthread_create and pthread_join when 2 <= t <= 3 to create additional POSIX
 * thread(s) to compute all diagonal sums. 
 * Do not alter this function prototype in any way.
 */
void diagonalSums(grid * input, unsigned long s, grid * output, int t);


/*
 * Write the contents of g to fileName in the present
 * working directory. If fileName exists in the present working directory, 
 * then this function should overwrite the contents in fileName.
 * If fileName does not exist in the present working directory,
 * then this function should create a new file named fileName
 * and assign read and write permissions to the owner. 
 * Do not alter this function prototype in any way.
 */
void writeGrid(grid * g, char * fileName);

/*
 * Free up all dynamically allocated memory used by g.
 * This function should be called when the program is finished using g.
 * Do not alter this function prototype in any way.
 */
void freeGrid(grid * g);

/*
 * You may add any additional function prototypes and any additional
 * things you need to complete this project below this comment. 
 * Anything you add to this file should be commented. 
 */





#endif

我试过:./proj4.out in5.txt out5.txt 1222 3; diff out5.txt 正确输出5.txt | wc -c;

我得到这个错误:

Segmentation fault (core dumped) diff: out5.txt: 没有那个文件或目录 0

我大致预计这是一个输出(时间使用会有所不同):

使用 3 个线程计算 3567×3567 网格中等于 1222 的对角线和。 使用 3 个线程计算对角线总和的耗时:61.737591 秒。 将等于 1222 的对角线和写入文件 out5.txt。 程序完成。再见! 0

我需要帮助来理解为什么会发生分段错误以及我可以做些什么来修复它。

c multithreading segmentation-fault grid diagonal
© www.soinside.com 2019 - 2024. All rights reserved.