You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C多线程文件读取问题求助:单线程处理一行且无重复读取

咱来看看你这段代码为啥没输出,问题还挺多的,我给你逐个拆解,再给你改好的版本:

问题分析

1. 函数嵌套定义(语法错误)

C标准不允许在函数内部定义其他函数,你把getLineCount和readLine都塞在main里了,很多编译器直接会报错,根本编译不过,这是第一个大问题。

2. 线程参数传递的致命bug

你在循环里把&i传给线程,但i是循环变量,所有线程共享这个地址。线程启动是异步的,等线程真正开始执行的时候,循环可能已经跑完了,所有线程拿到的lineN都是最后一个i的值,根本没法正确处理对应行。

3. 互斥锁的错误操作

  • 你只声明了pthread_mutex_t lock;但没初始化,应该调用pthread_mutex_init(&lock, NULL);才能正常使用锁。
  • 你在循环里创建一个线程就调用pthread_mutex_destroy(&lock);,这直接把锁销毁了,后续线程调用pthread_mutex_lock会直接出错,完全起不到互斥的作用。

4. 文件读取逻辑错误

每个线程都重新打开文件,逐行读到目标行,这效率极低。而且你用fgets读行之后,又调用fscanf,这时候fscanf会从fgets读过的下一行开始读,导致你读的数据根本不是目标行的内容,就算有输出也是错的。

5. 线程join的硬编码问题

你手动写了5个pthread_join,如果data.txt的行数不是5,要么有线程没被join(程序可能提前退出),要么访问tid数组越界(直接崩溃)。

6. 全局变量的不合理使用

a和b是全局变量,虽然有锁,但完全没必要,直接在函数里用局部变量就行,避免不必要的共享。

修正后的代码

我把这些问题都修复了,还优化了逻辑:让主线程先把所有行读进内存,然后每个线程处理对应索引的行,这样不用每个线程都打开文件,效率高很多。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>

// 全局结构体,用来给线程传递参数
typedef struct {
    int line_idx;
    char* line_content;
} ThreadData;

// 计算文件行数(移到main外面)
int getLineCount(const char* filename) {
    FILE *fp = fopen(filename, "r");
    if(fp == NULL) {
        printf("File does not exist!!!\n");
        return -1;
    }
    char ch;
    int linesCount = 0;
    // 处理最后一行没有换行符的情况
    int has_content = 0;
    while((ch = fgetc(fp)) != EOF) {
        has_content = 1;
        if(ch == '\n') {
            linesCount++;
        }
    }
    // 如果文件有内容且最后一行没换行,行数+1
    if(has_content && ch != '\n') {
        linesCount++;
    }
    fclose(fp);
    return linesCount;
}

// 线程处理函数(移到main外面)
void *readLine(void *arg) {
    ThreadData* data = (ThreadData*)arg;
    int a, b;
    // 从行内容里解析整数
    if(sscanf(data->line_content, "%d %d", &a, &b) == 2) {
        printf("Thread %d: %d + %d = %d\n", data->line_idx, a, b, a + b);
    } else {
        printf("Thread %d: Invalid line content\n", data->line_idx);
    }
    // 释放线程参数的内存
    free(data);
    pthread_exit(NULL);
}

int main() {
    const char* filename = "data.txt";
    int lineCount = getLineCount(filename);
    if(lineCount <= 0) {
        return 1;
    }

    // 先把所有行读进内存
    char** lines = (char**)malloc(lineCount * sizeof(char*));
    if(lines == NULL) {
        printf("Memory allocation failed!\n");
        return 1;
    }

    FILE* fp = fopen(filename, "r");
    if(fp == NULL) {
        printf("File does not exist!!!\n");
        free(lines);
        return 1;
    }

    char buffer[256];
    int i = 0;
    while(fgets(buffer, sizeof(buffer), fp) != NULL) {
        // 去掉换行符
        buffer[strcspn(buffer, "\n")] = '\0';
        lines[i] = (char*)malloc(strlen(buffer) + 1);
        strcpy(lines[i], buffer);
        i++;
    }
    fclose(fp);

    pthread_t tid[lineCount];
    for(i = 0; i < lineCount; i++) {
        // 为每个线程分配参数内存
        ThreadData* data = (ThreadData*)malloc(sizeof(ThreadData));
        data->line_idx = i + 1; // 行号从1开始
        data->line_content = lines[i];
        // 创建线程
        if(pthread_create(&tid[i], NULL, readLine, (void*)data) != 0) {
            printf("Failed to create thread %d\n", i + 1);
            free(data);
            // 出错了要释放已分配的内存
            for(int j = 0; j < i; j++) {
                pthread_join(tid[j], NULL);
                free(lines[j]);
            }
            free(lines);
            return 1;
        }
    }

    // 等待所有线程完成
    for(i = 0; i < lineCount; i++) {
        pthread_join(tid[i], NULL);
        free(lines[i]);
    }
    free(lines);

    return 0;
}
关键优化点
  • 把函数移到main外面,符合C标准语法。
  • 主线程提前读取所有行到内存,每个线程直接处理对应行,避免重复打开文件,效率更高。
  • 用结构体传递线程参数,每个线程有独立的参数内存,避免循环变量地址的问题。
  • 动态join所有线程,不管文件有多少行都能正确处理。
  • 去掉了不必要的互斥锁,因为线程之间不再共享文件操作,只处理自己的行数据。

内容的提问来源于stack exchange,提问作者Natalie112

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 07:43:03