【发布时间】:2019-04-06 20:02:42
【问题描述】:
我正在编写一个程序,用于使用 pthread 执行矩阵乘法。它通过指定矩阵大小n(假设矩阵为正方形)和线程数p(假设除以n 均匀。对于 A x B,A 被水平划分为 p 个段,每个线程接收一个段作为输入,并且整个矩阵 B 并返回结果矩阵 C 的一部分。
我遇到的问题实际上与分配本身无关,而是关于 pthread 的性质的更普遍的问题,我无法找到答案。我会尽量将其剥离。我的矩阵在结构中存储为一维数组。
typedef struct matrix {
int *matrix;
int size;
} matrix_t
它们是这样分配的
matrix_t mtx = {
malloc(input_size * input_size * sizeof(int)),
input_size
};
并由函数随机填充。分区存储在一个二维数组中,其地址是从函数返回的,但以正常方式分配:
int **partitions = partitionmtx(mtx, num_threads);
int **partitionmtx(matrix_t mtx, int threads)
{
int partlen = mtx.size * (mtx.size / threads);
int **parts = malloc(threads * sizeof(int));
for(int i = 0; i < threads; ++i) {
parts[i] = malloc(partlen * sizeof(int));
// partitions populated...
}
return parts;
}
这很好用。当我将每个分区发送到一个线程时,问题就出现了。为了使线程的参数保持简单,我将它们捆绑在一起:
typedef struct operand {
matrix_t matrix;
int *partition;
int partition_length;
} operand_t;
我正在像这样创建 pthread:
pthread_t threads[num_threads];
pthread_mutex_init(&mymutex, NULL);
int rc;
for(int i = 0; i < num_threads; ++i) {
operand_t op = {matrix, partitions[i], partition_length};
rc = pthread_create(&threads[i], NULL, partition_product, (void *)&op);
assert(rc == 0);
}
for(int i = 0; i < num_threads; ++i) {
rc = pthread_join(threads[i], NULL);
assert(rc == 0);
}
转到我的功能 partition_product。我的首要任务显然是确保每个线程都获取正确的数据,所以我打印了每个线程的内容:
void* partition_product(void *args)
{
operand_t *op = (operand_t *)args;
pthread_mutex_lock(&mymutex);
printf("Matrix:\n);
printmtx(op->matrix); // This is a function I defined but its details aren't relevant here
printf("\nPartition:" );
for(int i = 0; i < op->partition_length; ++i)
printf("%4d", op->partition[i]);
pthread_mutex_unlock(&mymutex);
}
这就是我的问题所在。矩阵从线程打印没有问题。问题是所有线程,一旦我指定多个线程,例如
./threadmatrix -n 4 -p 4
全部打印相同的分区。我认为这可能是从线程打印的副作用,因此打印上的互斥锁。然后我想在原始线程和创建的线程中打印每个分区 [i] 的地址以查看发生了什么,并且似乎每个线程从创建点接收相同的地址。我正在将数据输入线程,并且似乎能够毫无问题地对其进行操作,但它们都是相同的数据。具体来说,它们总是得到最后一个分区的地址。我已经尝试了我所知道的所有好的指针实践,但如果 partitions[i] 的地址为 0x00007ffffde234,那么来自上述调用的所有 4 个线程都会打印地址 0x00007ffffde234。我在高处和低处搜索了一些解释,但一无所获。我做错了什么?
【问题讨论】:
-
OT:关于
assert(rc == 0);这只会导致程序(崩溃/退出)并且不应该在生产代码中。建议使用:if( ( rc = pthread_create(&threads[i], NULL, partition_product, (void *)&op) != 0) { perror( "pthread_create failed" ); followed by cleanup activities followed byexit(EXIT_FAILURE); }`perror()会将您的错误信息和系统认为错误发生的文本原因输出到stderr。这对用户来说比通过assert()使程序崩溃 提供更多信息
标签: c multithreading pointers pthreads