我正在尝试用 C 语言实现一个带有一些线程的简单程序。具体来说,我希望每个线程只读取 CSV 文件的一部分(每行仅包含四个浮点数)并将读取的值放入矩阵中。因此,每个线程都有自己的矩阵,它们将从分配给它的行中读取的值放入其中。我能够做到这一点,但是当我尝试从每个线程打印每个矩阵时,输出很奇怪,因为某些线程与打印重叠。我认为这是一个并发问题,但我不知道并发是在打印控制台上还是在访问文件 CSV 中,所以实际上在这一点上,我不知道 CSV 行中的值是否正好加载到矩阵中。我把代码和输出都写在这里了。有人可以帮我吗?
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define NTHREADS 15
#define NTRAIN 135
#define NFEATURES 4
#define X_TRAIN_PATH "C:/Users/tecnico/Desktop/UniME/Materie/HPC/MPI/Programs/Multithreading/X_train.csv"
void checkFile(FILE *f) {
if (f == NULL) {
printf("Error while reading file\n");
exit(1);
}
}
float *getFloatMat(int m, int n) {
float *mat = NULL;
mat = (float *)calloc(m * n, sizeof(float));
return mat;
}
float *initFeatures(char path[], int start_row, int end_row) {
int index = 0;
FILE *f = NULL;
float *mat = NULL;
mat = getFloatMat(end_row - start_row + 1, NFEATURES);
f = fopen(path, "r");
checkFile(f);
// Skippa le righe prima di start_row
for (int i = 0; i < start_row; i++)
while (fgetc(f) != '\n')
;
// Leggi i dati dalla riga start_row alla riga end_row
for (int i = start_row; i <= end_row; i++) {
for (int j = 0; j < NFEATURES; j++) {
fscanf(f, "%f%*c", &mat[index]);
index++;
}
}
fclose(f);
return mat;
}
struct ThreadData {
int thread_id;
int start_row;
int end_row;
float *x_train;
};
void *threadFunction(void *arg) {
struct ThreadData *data = (struct ThreadData *)arg;
// Inizializza la matrice per il thread corrente
data->x_train = initFeatures(X_TRAIN_PATH, data->start_row, data->end_row);
// Stampa la matrice per il thread corrente
printf("Thread %d:\n", data->thread_id);
for (int i = 0; i <= data->end_row - data->start_row; i++) {
for (int j = 0; j < NFEATURES; j++) {
printf("%.2f ", data->x_train[i * NFEATURES + j]);
}
printf("\n\n");
}
// Libera la memoria allocata per la matrice
free(data->x_train);
pthread_exit(NULL);
}
int main(int argc, char const *argv[]) {
pthread_t threads[NTHREADS];
struct ThreadData thread_data[NTHREADS];
int rows_per_thread = NTRAIN / NTHREADS;
// Creazione e avvio dei thread
for (int i = 0; i < NTHREADS; i++) {
thread_data[i].thread_id = i;
thread_data[i].start_row = i * rows_per_thread + 1;
thread_data[i].end_row = (i + 1) * rows_per_thread;
pthread_create(&threads[i], NULL, threadFunction, (void *)&thread_data[i]);
}
// Attesa della terminazione dei thread
for (int i = 0; i < NTHREADS; i++) {
pthread_join(threads[i], NULL);
}
return 0;
}
这是输出:
主题 8: 6.00 2.70 5.10 1.60
6.10 3.00 4.90 1.80
5.90 线程 13: 5.40 3.40 1.50 0.40
5.50 3.50 1.30 0.20
6.70 3.00 5.20 2.30
5.50 2.40 3.80 1.10
4.80 3.40 1.90 0.20
4.60 线程 9: 6.00 3.60 1.00 0.20
5.20 3.50 1.50 0.20
4.90 3.00 1.40 0.20
5.40 3.00 4.50 1.50
3.00 4.80 1.80
6.30 2.70 4.90 1.80
6.40 2.90 4.30 1.30
5.10 3.50 1.40 0.30
6.60 2.90 4.60 1.30
6.80 2.80 4.80 1.40
5.40 3.90 1.70 0.40
5.20 3.40 1.40 0.20
4.80 3.00 1.40 0.30
主题 5: 4.80 3.00 1.40 0.10
5.80 2.80 5.10 2.40
5.80 2.70 4.10 1.00
4.90 2.40 3.30 1.00
6.20 2.80 4.80 1.80
5.00 3.40 1.50 0.20
6.80 3.00 5.50 2.10
5.60 2.50 3.90 1.10
5.60 2.80 4.90 2.00
线程 0: 4.80 线程 1: 3.40 1.60 0.20
5.80 2.70 3.90 1.20
6.70 3.30 5.70 2.50
6.10 3.00 4.60 1.40
6.40 3.20 5.30 2.30
7.30 2.90 6.30 1.80
5.70 2.80 4.10 1.30
5.50 4.20 1.40 0.20
6.70 3.10 5.60 2.40
主题 4: 5.80 2.60 4.00 1.20
5.60 3.00 4.10 1.30
5.50 2.50 4.00 1.30
5.80 2.70 5.10 1.90
5.00 3.30 1.40 0.20
5.10 2.50 3.00 1.10
4.90 3.10 1.50 0.10
5.10 3.80 1.90 0.40
5.60 2.70 4.20 1.30
主题 11: 6.40 2.70 5.30 1.90
5.70 3.80 1.70 0.30
6.90 3.10 5.40 2.10
7.70 2.60 6.90 2.30
6.10 2.80 4.70 1.20
6.30 3.40 5.60 2.40
7.70 3.00 6.10 2.30
6.80 3.20 5.90 2.30
4.60 3.40 1.40 0.30
3.00 5.10 1.80
5.50 2.30 4.00 1.30
5.70 2.50 5.00 2.00
6.50 3.00 5.50 1.80
5.90 3.20 4.80 1.80
6.10 2.60 5.60 1.40
6.90 3.10 5.10 2.30
主题 2: 6.00 3.40 4.50 1.60
5.60 3.00 4.50 1.50
5.40 3.90 1.30 0.40
6.90 3.10 4.90 1.50
4.90 2.50 4.50 1.70
6.40 2.80 5.60 2.10
6.00 2.90 4.50 1.50
5.00 2.30 3.30 1.00
7.20 3.60 6.10 2.50
6.70 3.00 5.00 1.70
5.40 3.40 1.70 0.20
6.10 2.90 4.70 1.40
5.00 3.00 1.60 0.20
5.70 3.00 4.20 1.20
5.00 3.50 1.60 0.60
5.20 2.70 3.90 1.40
6.90 3.20 5.70 2.30
7.40 2.80 6.10 1.90
主题 6: 5.10 3.40 1.50 0.20
5.20 4.10 1.50 0.10
6.30 2.90 5.60 1.80
6.70 3.30 5.70 2.10
5.70 2.80 4.50 1.30
7.10 3.00 5.90 2.10
6.40 3.10 5.50 1.80
7.20 3.20 6.00 1.80
6.00 2.20 4.00 1.00
主题 3: 5.10 3.80 1.60 0.20
4.50 2.30 1.30 0.30
4.90 3.10 1.50 0.10
6.30 3.30 4.70 1.60
4.40 3.20 1.30 0.20
6.30 3.30 6.00 2.50
7.20 3.00 5.80 1.60
4.80 3.10 1.60 0.20
6.30 2.50 5.00 1.90
主题 14: 5.00 3.40 1.60 0.40
6.50 3.00 5.20 2.00
5.00 3.50 1.30 0.30
4.70 3.20 1.60 0.20
5.70 2.90 4.20 1.30
5.50 2.40 3.70 1.00
6.40 2.80 5.60 2.20
6.30 2.80 5.10 1.50
0.00 0.00 0.00 0.00
主题 7: 6.20 2.90 4.30 1.30
6.50 3.00 5.80 2.20
7.70 2.80 6.70 2.00
4.30 3.00 1.10 0.10
5.80 2.70 5.10 1.90
6.30 2.50 4.90 1.50
5.10 3.80 1.50 0.30
4.40 2.90 1.40 0.20
6.70 2.50 5.80 1.80
主题 10: 5.80 4.00 1.20 0.20
4.60 3.20 1.40 0.20
7.00 3.20 4.70 1.40
6.20 3.40 5.40 2.30
6.60 3.00 4.40 1.40
5.90 3.00 4.20 1.50
6.70 3.10 4.70 1.50
5.00 3.20 1.20 0.20
5.70 2.60 3.50 1.00
主题 12: 6.70 3.10 4.40 1.40
5.40 3.70 1.50 0.20
6.30 2.30 4.40 1.30
6.50 2.80 4.60 1.50
5.00 2.00 3.50 1.00
6.50 3.20 5.10 2.00
7.60 3.00 6.60 2.10
6.40 3.20 4.50 1.50
4.60 3.10 1.50 0.20
这是 CSV 文件
您遇到一些打印问题,因为正如您所说,某些线程与打印重叠,所有线程都同时打印,因此您的输入完全正常。
如果你想避免这种情况,你可以使用互斥锁,在打印之前锁定它,并在“打印之后解锁它” " 打印或者您可以使用 snprintf 一次打印所有行
使用示例:
#include <stdio.h>
int main() {
int number = 123;
char character = 'A';
char *string = "Hello";
char buffer[100]; // Make sure the buffer can contain all the character
sprintf(buffer, "Number: %d, Character: %c, String: %s", number, character, string);
printf("Formatted String: %s\n", buffer);
return 0;
}