提问人:dev jonston 提问时间:11/7/2023 最后编辑:dev jonston 更新时间:11/7/2023 访问量:50
在 C 语言中实现矩阵加法
implementing matrix addition in c
问:
我目前正在学习如何在 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;
}
答: 暂无答案
评论