Я пишу программу для назначения для выполнения умножения матриц с использованием pthreads.Он работает путем указания размера матрицы n (матрицы считаются квадратными) и количества потоков p , которое предполагается делить n равномерно.Для A x B , A горизонтально разделено на сегменты p , и каждый поток получает в качестве входных данных отдельный сегмент и всю матрицу B и возвращает часть полученной матрицы C .
Проблема, с которой я столкнулся, заключается не в самом назначении, а в более общей проблеме природы потоков, на которую я не смог найти ответ.Я постараюсь раздеть это как можно больше.Мои матрицы хранятся в виде 1D-массивов внутри структуры.
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;
Я создаю pthreads примерно так:
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.Я искал высоко и низко какое-то объяснение и ничего не нашел.Что я делаю не так?