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

多线程处理文本整数质数筛选:线程重复执行问题求助

多线程处理多文件质数筛选出现重复写入与执行异常问题

我需要通过多线程从3个文本文件读取整数值,判断质数后写入新文件。功能函数本身能正常工作,但线程创建的循环逻辑有问题,导致线程重复执行、执行次数异常,程序持续写入重复值,无法正确完成1159999个数值的处理与存储。

现有代码如下:

#include <stdlib.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
pthread_mutex_t lck;
typedef struct{
int start;
int end;
}Innerstruct;

struct data{
FILE **fptr;
Innerstruct *inner;
int numberthreads;
int totalno;
};

int primecount=0;//to store prime numbers count
int nofiles=3;

void countlines(int *count,FILE **fptr,int nofiles){ //counts the no of lines of cordinates from the text file
int i;
*count = 0;
for(i=0;i<nofiles;i++){
    fseek(fptr[i], 0, SEEK_SET);
    char line[256]; // buffer to store each line
      while(fgets(line, sizeof(line), fptr[i])){
        if(strlen(line) > 1){ // only increment if line is not empty so that this doesn't count blank spaces            (*count)++;
        }
    }
}

}

 void *getstorecountprime(void *p){
FILE *fptr4;
fptr4 = fopen("PrimeNumber.txt","w");
if(fptr4==NULL){
    printf("Error creating file");
}
struct data *d1 = p;
int i,j,k,num,start,end;
for(k=0;k<d1->numberthreads;k++){
    start= d1->inner[k].start;
    end = d1->inner[k].end;

    for(j=start;j<=end;j++){
    for(i=0;i<nofiles;i++){
        fseek(d1->fptr[i], j, SEEK_SET);
        fscanf(d1->fptr[i],"%d",&num);

         if(checkprime(num)){
        pthread_mutex_lock(&lck);
        fprintf(fptr4,"%d\n",num);
        primecount++;
        pthread_mutex_unlock(&lck);
          }
    }
  }
  }

}

void main(){
//checking for any error on opening the files
FILE *fptr1,*fptr2,*fptr3;
// opening text files
fptr1 = fopen("PrimeData1.txt","r");
fptr2 = fopen("PrimeData2.txt","r");
fptr3 = fopen("PrimeData3.txt","r");
if(fptr1==NULL || fptr2==NULL || fptr3==NULL){
    printf("Could not open all files");
    exit(1);
}

pthread_mutex_init(&lck,NULL);
FILE *fptr[] = {fptr1,fptr2,fptr3}; //array of file pointer
int num_threads,sliceperthread,*numarray;
int i;

int totalcount = 0;//to store total numbers
pthread_t *id;
struct data d1;
countlines(&totalcount,fptr,nofiles);//counts the no of lines from txt files
numarray = malloc(totalcount*sizeof(int));//dma to store all datas in array

printf("Enter how many threads do you want:");
scanf("%d",&num_threads);


id = malloc(num_threads*sizeof(pthread_t));//dma thread equal to the number of thread
d1.inner = malloc(num_threads*sizeof(Innerstruct));//dma the inner structure containing start and end

d1.fptr = malloc(nofiles*sizeof(FILE*));//dma the fptr as array of nofiles size
sliceperthread = totalcount/num_threads;
d1.fptr=fptr;//assigned the fptr of structure to array of file pointer created above
d1.numberthreads=num_threads;
d1.totalno = totalcount;
d1.inner[0].start = 0;
d1.inner[0].end = sliceperthread;

for(i=1;i<=num_threads;i++){
    d1.inner[i].start = d1.inner[i-1].end + 1;
    d1.inner[i].end = d1.inner[i-1].end + sliceperthread;
}

for(i=0;i<num_threads;i++){
    pthread_create(&id[i],NULL,getstorecountprime,&d1);
    pthread_join(id[i],NULL);
}
printf("%d",primecount);
}


 int checkprime(int n){
int i;
for(i=2;i<=n/2;i++){
     if(n%i == 0){
    return 0;
     }else{
    return 1;
    }
}
}

核心问题梳理

  1. 线程任务重复执行:每个线程都遍历所有线程的任务区间(for(k=0;k<d1->numberthreads;k++)),导致所有线程重复处理全部数据,这是重复写入的核心原因。
  2. 文件打开模式错误:每个线程用"w"模式打开输出文件,会清空之前的内容,多线程同时打开还会引发竞态问题。
  3. 文件定位逻辑错误:fseek按字节偏移,而非行偏移,用行数j定位会读取到错误数值。
  4. 线程串行执行:创建线程后立即pthread_join,导致线程无法并行,失去多线程意义。
  5. 质数判断逻辑失效:checkprime第一次循环就返回结果,比如n=9会被误判为质数。
  6. 数组越界访问:任务区间循环for(i=1;i<=num_threads;i++)会访问超出分配范围的数组元素。
  7. 内存泄漏:多处malloc的内存未释放,文件未关闭。

修复后的代码

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

pthread_mutex_t lck;
int primecount = 0;
int nofiles = 3;

// 单线程任务参数结构体
typedef struct {
    int *numarray;
    int start_line;
    int end_line;
    FILE *out_fptr;
} ThreadData;

// 统计所有文件的总行数
void count_total_lines(int *totalcount, FILE **fptr) {
    *totalcount = 0;
    char line[256];
    for (int i = 0; i < nofiles; i++) {
        fseek(fptr[i], 0, SEEK_SET);
        while (fgets(line, sizeof(line), fptr[i])) {
            if (strlen(line) > 1) (*totalcount)++;
        }
    }
}

// 加载所有文件的数值到数组
void load_numbers_to_array(int *numarray, FILE **fptr) {
    int idx = 0;
    char line[256];
    for (int i = 0; i < nofiles; i++) {
        fseek(fptr[i], 0, SEEK_SET);
        while (fgets(line, sizeof(line), fptr[i])) {
            if (strlen(line) > 1) {
                sscanf(line, "%d", &numarray[idx++]);
            }
        }
    }
}

// 修正后的质数判断函数
int checkprime(int n) {
    if (n <= 1) return 0;
    if (n == 2) return 1;
    if (n % 2 == 0) return 0;
    for (int i = 3; i <= sqrt(n); i += 2) {
        if (n % i == 0) return 0;
    }
    return 1;
}

// 线程处理函数:仅处理分配给自己的区间
void *process_prime(void *arg) {
    ThreadData *data = (ThreadData *)arg;
    int num;

    for (int j = data->start_line; j < data->end_line; j++) {
        num = data->numarray[j];
        if (checkprime(num)) {
            pthread_mutex_lock(&lck);
            fprintf(data->out_fptr, "%d\n", num);
            primecount++;
            pthread_mutex_unlock(&lck);
        }
    }
    pthread_exit(NULL);
}

int main() {
    // 打开输入文件
    FILE *fptr1 = fopen("PrimeData1.txt", "r");
    FILE *fptr2 = fopen("PrimeData2.txt", "r");
    FILE *fptr3 = fopen("PrimeData3.txt", "r");
    if (!fptr1 || !fptr2 || !fptr3) {
        printf("Could not open all files\n");
        exit(1);
    }
    FILE *fptr[] = {fptr1, fptr2, fptr3};

    pthread_mutex_init(&lck, NULL);
    int totalcount = 0;
    count_total_lines(&totalcount, fptr);

    // 加载所有数值到数组,避免线程中重复操作文件
    int *numarray = malloc(totalcount * sizeof(int));
    if (!numarray) {
        printf("Malloc failed for numarray\n");
        exit(1);
    }
    load_numbers_to_array(numarray, fptr);

    // 获取线程数量
    int num_threads;
    printf("Enter how many threads do you want: ");
    scanf("%d", &num_threads);

    // 分配线程和任务参数内存
    pthread_t *threads = malloc(num_threads * sizeof(pthread_t));
    ThreadData *thread_datas = malloc(num_threads * sizeof(ThreadData));
    if (!threads || !thread_datas) {
        printf("Malloc failed for threads/thread_datas\n");
        exit(1);
    }

    // 主线程打开输出文件,统一传递给所有线程
    FILE *out_fptr = fopen("PrimeNumber.txt", "w");
    if (!out_fptr) {
        printf("Error creating output file\n");
        exit(1);
    }

    // 分配每个线程的处理区间
    int slice = totalcount / num_threads;
    for (int i = 0; i < num_threads; i++) {
        thread_datas[i].numarray = numarray;
        thread_datas[i].start_line = i * slice;
        // 最后一个线程处理剩余所有数据,避免遗漏
        thread_datas[i].end_line = (i == num_threads - 1) ? totalcount : (i + 1) * slice;
        thread_datas[i].out_fptr = out_fptr;
        pthread_create(&threads[i], NULL, process_prime, &thread_datas[i]);
    }

    // 等待所有线程执行完成
    for (int i = 0; i < num_threads; i++) {
        pthread_join(threads[i], NULL);
    }

    printf("Total primes found: %d\n", primecount);

    // 释放所有资源
    fclose(fptr1);
    fclose(fptr2);
    fclose(fptr3);
    fclose(out_fptr);
    free(numarray);
    free(threads);
    free(thread_datas);
    pthread_mutex_destroy(&lck);

    return 0;
}

关键修复说明

  • 任务拆分优化:每个线程仅处理分配给自己的区间,避免重复处理数据。
  • 数据预加载:先将所有文件的数值读取到数组,线程直接从数组读取,解决文件定位错误问题,提升效率。
  • 质数判断修正:修复判断逻辑,正确识别质数。
  • 输出文件单例化:主线程统一打开输出文件,传递给所有线程,避免多线程重复打开清空文件。
  • 并行执行实现:先创建所有线程,再统一等待完成,真正实现多线程并行处理。
  • 边界处理修正:最后一个线程处理剩余所有数据,避免遗漏;修正数组访问边界,防止越界。
  • 资源清理:添加所有内存释放、文件关闭、互斥锁销毁操作,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 14:41:45