在 C 语言中实现矩阵加法

implementing matrix addition in c

提问人:dev jonston 提问时间:11/7/2023 最后编辑:dev jonston 更新时间:11/7/2023 访问量:50

问:

我目前正在学习如何在 c 中实现线程和矩阵,并且在实现使用两个线程执行矩阵加法的函数时遇到困难。下面的代码是我目前正在使用的函数,以及用于测试我的实现的测试文件。程序从命令行获取行数和列数,用随机数填充两个矩阵,并比较 addMatrix() 和 addMatrix thread() 的结果,如果未指定参数,程序将处理大小为 6 × 6 的矩阵。我一直得到不正确的答案以及分段故障 - 核心转储 (./test-madd element[0][0] 2978345935.0000000 0.000000。结果不匹配。并且不确定为什么?我对线程很陌生,所以老实说,我不知道我哪里出了问题。

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

#define     NUM_THREADS     2

typedef struct {
    unsigned int id;
    TMatrix *m, *n, *t;
} thread_arg_t;

/* the main function of threads */
static void * thread_main(void * p_arg)
{
 
    thread_arg_t *arg = (thread_arg_t *)p_arg;
    unsigned int id = arg ->id;
    unsigned int start = id * (arg -> m -> nrows / NUM_THREADS);
    unsigned int end = (id + 1) * (arg -> m -> nrows / NUM_THREADS);

    unsigned int i = start;

    while (i == start && i < end) {
        unsigned int j = 0;
        while (j == 0 && j < arg->m->ncols) {
            arg->t->data[i][j] = arg->m->data[i][j] + arg->n->data[i][j];
            j++;
        }
        i++;
    }
    return NULL;
}

/* Return the sum of two matrices. The result is in a newly creaed matrix. 
 *
 * If a pthread function fails, report error and exit. 
 * Return NULL if something else is wrong.
 *
 * Similar to addMatrix, but this function uses 2 threads.
 */
TMatrix * addMatrix_thread(TMatrix *m, TMatrix *n)
{
    if (    m == NULL || n == NULL
         || m->nrows != n->nrows || m->ncols != n->ncols )
        return NULL;

    TMatrix * t = newMatrix(m->nrows, m->ncols);
    if (t == NULL)
        return t;

    thread_arg_t args[NUM_THREADS];
    pthread_t threads[NUM_THREADS];

    unsigned int i = 0;
    while(i < NUM_THREADS){
        args[i].id = i;
        args[i].m = m;
        args[i].n = n;
        args[i].t = t;
        i++;
    }
    if(pthread_create(&threads[i], NULL, thread_main, &args[i]) != 0){
        fprintf(stderr, "Error creating thread\n");
        exit(EXIT_FAILURE);
    }

    while(i < NUM_THREADS){
        if(pthread_join(threads[i], NULL) != 0){
            fprintf(stderr, "Error joining thread\n");
            exit(EXIT_FAILURE);
        }
        i++;
    }
    
    return t;
}

以下是我的测试用例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/time.h>
#include "matrix.h"

/* timing functions */
void    stopwatch_start();
double  stopwatch_read();

#define     DEFAULT_NROWS    6
#define     DEFAULT_NCOLS    6

static void check_pointer(void *p, char *s)
{
    if (p)
       return; 
    fprintf(stderr, "%s: Pointer is NULL.\n", s ? s : "");
    exit(EXIT_FAILURE);
}

int main(int argc, char ** argv)
{
    int     nrows = DEFAULT_NROWS;
    int     ncols = DEFAULT_NCOLS;
    int     show_time = 0;
    int     count = 0;

    for (int i = 1; i < argc; i++) {
        if (strncmp(argv[i], "-t", 2) == 0) {
            show_time = atoi(&argv[i][2]);
            if (show_time <= 0) {
                fprintf(stderr, "Number of runs must be a positive integer: %s\n", &argv[i][2]);
                exit(EXIT_FAILURE);
            }
        } else if (isdigit(argv[i][0]) && count < 2) { 
            if (count == 0)
                nrows = atoi(argv[i]);
            else if (count == 1)
                ncols= atoi(argv[i]);
            count ++;
        } else {
            fprintf(stderr, "Usage: %s [nrows [ncols]] [-t]\n"
                            "<nrows> : number of rows. Default value is %d.\n"
                            "<ncols> : number of columns. Default value is %d.\n"
                            "-t      : show execution time.\n"
                            , argv[0], DEFAULT_NROWS, DEFAULT_NCOLS);
            return 1;
        }
    }

    if (! (nrows > 0 && ncols > 0)) {
        fprintf(stderr, "Both nrows and ncols must be positive integers: nrows=%d ncols=%d\n", nrows, ncols);
        exit(EXIT_FAILURE);
    }

    double  time1, time2;

    TMatrix *m, *n;

    m = newMatrix(nrows, ncols);
    check_pointer(m, "m");
    n = newMatrix(nrows, ncols);
    check_pointer(n, "n");

    fillMatrix(m);
    fillMatrix(n);

    TMatrix *t1, *t2;
    stopwatch_start();
    t1 = addMatrix(m, n);
    check_pointer(t1, "t1");
    for (int i = 1; i < show_time; i ++) {
        freeMatrix(t1);
        t1 = addMatrix(m, n);
        check_pointer(t1, "t1");
    }
    time1 = stopwatch_read();
    
    stopwatch_start();
    t2 = addMatrix_thread(m, n);
    check_pointer(t2, "t2");
    for (int i = 1; i < show_time; i ++) {
        freeMatrix(t2);
        t2 = addMatrix_thread(m, n);
        check_pointer(t2, "t2");
    }
    time2 = stopwatch_read();

    int     r = compareMatrix(t1, t2);

    freeMatrix(m);
    freeMatrix(n);
    freeMatrix(t1);
    freeMatrix(t2);

    if (r) {
        printf("%s\n", "Results do not match.");
        exit(EXIT_FAILURE);
    } else {
        printf("%s\n", "Good work!");
    }

    if (show_time) {
        double speedup = 0;
        // only computes speedup if time2 is longer than 1ms
        if (time2 > 0.001) {
            speedup = time1/time2;
        }
        time1 /= show_time;
        time2 /= show_time;
        printf("num_runs=%d time1=%.4f time2=%.4f speedup=%.4f\n", show_time, time1, time2, speedup);
    }
    return 0;
}

/*********** Implementation of a timer ****************/
#define     MAX_RUN_TIME    1000000

#define     TIMER_TYPE  ITIMER_REAL
// #define      TIMER_TYPE  ITIMER_PROF

// start a stop watch, using system timer
void stopwatch_start()
{
    struct itimerval pval;

    /* set the timer*/
    pval.it_value.tv_sec = MAX_RUN_TIME;
    pval.it_value.tv_usec = 0;
    /* No repeating */
    pval.it_interval.tv_sec = 0;     
    pval.it_interval.tv_usec = 0;
    if (setitimer(TIMER_TYPE, &pval, NULL)) {
        fprintf(stderr, "Error: setitimer() failed.\n");
        exit(EXIT_FAILURE);
    }
}

/* Returns the number of seconds since last call to start_timer() 
 * The meaning of seconds depends on the timer type.
 * */
double stopwatch_read()
{
    struct itimerval val;
    long secs, usecs;
    double temp;

    if (getitimer(TIMER_TYPE, &val)) {
        fprintf(stderr, "Error: getitimer() failed.\n");
        exit(EXIT_FAILURE);
    }
    secs = MAX_RUN_TIME - val.it_value.tv_sec - 1;
    usecs = 1000000 - val.it_value.tv_usec;

    temp = (double) secs + ((double) usecs/1000000.0);

    return (temp > 0 ? temp : 0.0 );
}

我已经厌倦了不同的实现,其中我更改了 while 循环的条件,如下所示。我也尝试将 while 循环更改为 for 循环,但这也没有用。


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

#define     NUM_THREADS     2

typedef struct {
    unsigned int id;
    TMatrix *m, *n, *t;
} thread_arg_t;

/* the main function of threads */
static void * thread_main(void * p_arg)
{
    thread_arg_t *arg_t = p_arg;
    int rows = arg_t ->n ->nrows;
    int cols = arg_t ->m ->ncols;
    TMatrix * t = arg_t -> t;
    TMatrix * m = arg_t -> m;
    TMatrix * n = arg_t -> n;
    int i = 0;
    while(i < rows){
        int j = 0;
        while(j < cols){
            if(i % 2 == arg_t ->id){
                t ->data[i][j] = m ->data[i][j] + n ->data[i][j]
            }
            j++;
        }
        i++;
        j = 0;
    }
    pthread_exit(NULL);
    return NULL;
}

/* Return the sum of two matrices. The result is in a newly creaed matrix. 
 *
 * If a pthread function fails, report error and exit. 
 * Return NULL if something else is wrong.
 *
 * Similar to addMatrix, but this function uses 2 threads.
 */
TMatrix * addMatrix_thread(TMatrix *m, TMatrix *n)
{
    if (    m == NULL || n == NULL
         || m->nrows != n->nrows || m->ncols != n->ncols )
        return NULL;

    TMatrix * t = newMatrix(m->nrows, m->ncols);
    if (t == NULL)
        return t;

    thread_arg_t args[NUM_THREADS];
    pthread_t threads[NUM_THREADS];
    
    for(i = 0; i < NUM_THREADS; i++){
        args[i].id = i;
        args[i].m = m;
        args[i].n = n;
        args[i].t = t;
        rc = pthread_create(&thread[i], NULL, thread_main, &id[i]);
        if(rc){
            printf("ERROR; return code from pthread_create() is %d\n", rc);
            exit(-1);
        }
    }
    
    for(int j = 0; j < NUM_THREADS; j++) {
        pthread_join(threads[j], NULL);
        if(rc){
            printf("ERROR; return code from pthread_create() is %d\n", rc);
            exit(-1);
        }
    }
    
    return t;
}
c 线程

评论

0赞 Scott Hunter 11/7/2023
调试器是查找错误的绝佳工具。
0赞 Ted Lyngmo 11/7/2023
此外,如果您需要调试帮助。确保您提供我们可以编译和运行的代码。阅读有关创建最小可重现示例的信息。

答: 暂无答案