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

线程版麦克劳林公式文件读写异常:仅处理首个角度,文件读取为空

问题排查:基于pthread的麦克劳林展开计算程序异常分析

编写的基于pthread的C程序,用于通过麦克劳林展开计算角度的sin和cos值,支持输入多个角度,但运行时输入1.0、0.2、0.4三个角度后,终端仅输出首个角度的sin和cos结果,其余角度未被处理;调用q10readfile()读取angles.dat文件时返回空内容。

核心问题分析

1. 二进制与文本数据混合存储导致格式混乱

程序先写入二进制float角度数据到文件,后续线程又写入文本字符串结果,造成文件内容格式混杂:

  • 线程读取时,读完原始二进制角度后,会将后续文本字节解析为float,得到无效角度值,计算出的term绝对值直接小于阈值1e-15,循环提前退出,无法输出有效结果。
  • q10readfile()读取文件时,二进制float数据中可能包含\0字符,导致printf输出时提前截断,呈现为空内容。

2. 线程重复读取与文件偏移干扰

两个线程独立打开文件,均从文件开头读取数据:

  • 第一个线程处理完所有角度后写入文本到文件末尾,第二个线程打开文件后会重复读取原始角度,同时读取第一个线程写入的文本内容(解析为无效float),引发输出混乱或异常。
  • O_APPEND标志仅影响写操作偏移量,读操作仍按顺序进行,但混合写入进一步破坏了文件的可读取性。

3. 数组越界风险

线程读取无效float数据时,counter持续递增,超出malloc分配的数组大小,导致数组越界访问,引发未定义行为(如程序崩溃、输出异常)。

4. 文件关闭逻辑无效

全局flag变量用于控制文件关闭,但每个线程独立持有文件描述符,一个线程关闭自身描述符不影响另一个线程,此逻辑完全无效,还可能导致文件描述符泄漏。

修复方案

关键优化方向

  • 移除不必要的文件IO,直接通过内存数组传递角度数据。
  • 分离数据存储与结果输出,使用纯文本文件存储计算结果。
  • 修正线程分工,避免重复处理数据,用互斥锁保护共享数组的写入。

修改后的完整代码

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <math.h>

// 补充原代码缺失的幂运算和阶乘函数
double q7gptpower(double base, int exp) {
    return pow(base, exp);
}

unsigned long long q7gptfactorial(int n) {
    unsigned long long result = 1;
    for (int i = 1; i <= n; i++) {
        result *= i;
    }
    return result;
}

// Function declarations
void q10();
void *q10gptsin_maclaurin(void *arg);
void *q10gptcos_maclaurin(void *arg);
void q10readfile();

// Global variables
pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;
int angle_count = 0; // 存储角度总数,供线程使用

int main() {
    q10();
    q10readfile();
    return 0;
}

void q10() {
    int choice;
    // 初始化结果文件(清空原有内容)
    FILE* result_file = fopen("/home/endlessparadox/Documents/vs code/angles_result.dat", "w");
    if (!result_file) {
        perror("fopen result file");
        return;
    }
    fclose(result_file);

    printf("Enter how many angles:\n");
    scanf("%i", &choice);
    angle_count = choice;

    // 分配存储角度、sin值、cos值的数组
    float(*array)[3] = malloc(choice * sizeof(*array));
    if (!array) {
        perror("malloc");
        return;
    }

    // 读取用户输入的角度
    for (int i = 1; i <= choice; i++) {
        printf("Enter angle %i:\n", i);
        scanf("%f", &array[i - 1][0]);
    }

    // 创建线程计算sin和cos
    pthread_t sin_thread;
    pthread_t cos_thread;
    pthread_create(&sin_thread, NULL, q10gptsin_maclaurin, (void *)array);
    pthread_create(&cos_thread, NULL, q10gptcos_maclaurin, (void *)array);
    pthread_join(sin_thread, NULL);
    pthread_join(cos_thread, NULL);

    // 将结果写入文本文件并打印到终端
    result_file = fopen("/home/endlessparadox/Documents/vs code/angles_result.dat", "a");
    if (!result_file) {
        perror("fopen result file");
        free(array);
        return;
    }
    for (int i = 0; i < choice; i++) {
        fprintf(result_file, "Angle: %f Sin: %lf Cos: %lf\n", array[i][0], array[i][1], array[i][2]);
        printf("Angle: %f Sin: %lf Cos: %lf\n", array[i][0], array[i][1], array[i][2]);
    }
    fclose(result_file);
    free(array);
}

void *q10gptsin_maclaurin(void *arg) {
    float(*array)[3] = (float(*)[3])arg;
    for (int i = 0; i < angle_count; i++) {
        double sin_value = 0.0;
        double term;
        int n = 0;
        float angle = array[i][0];
        
        // 麦克劳林展开计算sin
        do {
            term = q7gptpower(angle, 2 * n + 1) / q7gptfactorial(2 * n + 1);
            if (n % 2 != 0) {
                term = -term; // 交替符号
            }
            sin_value += term;
            n++;
        } while (fabs(term) > 1e-15);

        // 互斥锁保护数组写入,避免竞争
        pthread_mutex_lock(&mylock);
        array[i][1] = sin_value;
        pthread_mutex_unlock(&mylock);
    }
    return NULL;
}

void *q10gptcos_maclaurin(void *arg) {
    float(*array)[3] = (float(*)[3])arg;
    for (int i = 0; i < angle_count; i++) {
        double cos_value = 0.0;
        double term;
        int n = 0;
        float angle = array[i][0];
        
        // 麦克劳林展开计算cos
        do {
            term = q7gptpower(angle, 2 * n) / q7gptfactorial(2 * n);
            if (n % 2 != 0) {
                term = -term; // 交替符号
            }
            cos_value += term;
            n++;
        } while (fabs(term) > 1e-15);

        // 互斥锁保护数组写入
        pthread_mutex_lock(&mylock);
        array[i][2] = cos_value;
        pthread_mutex_unlock(&mylock);
    }
    return NULL;
}

void q10readfile() {
    FILE* result_file = fopen("/home/endlessparadox/Documents/vs code/angles_result.dat", "r");
    if (!result_file) {
        perror("fopen result file");
        return;
    }
    char buffer[9999];
    printf("Text file contents:\n");
    // 逐行读取并打印结果文件
    while (fgets(buffer, sizeof(buffer), result_file)) {
        printf("%s", buffer);
    }
    fclose(result_file);
}

修复要点说明

  • 移除了原代码中二进制角度文件的读写,直接通过内存数组传递角度,避免格式冲突。
  • 新增angle_count全局变量传递角度数量,线程无需依赖文件获取数据。
  • 线程仅负责计算对应三角函数值,通过互斥锁保护共享数组的写入操作,消除竞争条件。
  • 使用单独的纯文本文件存储计算结果,q10readfile()读取纯文本内容,确保输出正常。
  • 补充了原代码缺失的幂运算和阶乘函数,解决编译依赖问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 00:22:02