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

运行多线程C程序触发段错误的原因排查及代码求助

问题描述

编写了一个包含两个线程的C程序:线程A负责读取文件内容并共享给线程B,线程B接收数据后统计文件中的字节数量。程序使用信号量实现线程间通信,两个线程能正常运行,但程序即将终止时触发内存段错误。

原代码

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#define BUFFER_SIZE 4096
typedef struct _Buffer
{
    int size;
    char data[BUFFER_SIZE];
} Buffer;

sem_t task1, task2;

void *thread_A(void *arg);
void *thread_B(void *arg);
int main(int argc, char *argv[])
{
    
    Buffer *memory = malloc(sizeof(Buffer));

    sem_init(&task1, 0, 0);
    sem_init(&task2, 0, 0);

    pthread_t thread_A_id;
    pthread_t thread_B_id;

    pthread_create(&thread_A_id, NULL, &thread_A,  &memory);

    pthread_create(&thread_B_id, NULL, &thread_B,  &memory);
    
    if (pthread_join(thread_A_id, NULL) != 0)
    {
        perror("Error joining thread A");
        exit(1);
    }

    if (pthread_join(thread_B_id, NULL) != 0)
    {
        perror("Error joining thread B");
        exit(1);
    }

    free(memory);
    return 0;
}

void *thread_A(void *arg)
{
    Buffer *buffer = (Buffer*) arg;

    FILE *pdf_file = fopen("file.pdf", "rb");
    if (pdf_file == NULL)
    {
        perror("Can not open the file");
    }

    printf("size of struct %ld\n", sizeof(Buffer));
    buffer->size = fread(&buffer->data, sizeof(char), BUFFER_SIZE, pdf_file);

    fclose(pdf_file);

    sem_post(&task1); 
   
    sem_wait(&task2);
    printf("A is out\n");
    return NULL;
}

void *thread_B(void *arg)
{
    printf("IAM IN TREAD B\n");
    Buffer *buffer = (Buffer*) arg;
    
    sem_wait(&task1);
    int i=0;

    int byte_counts[256] = {0};
    while (buffer->size != i) {
                    
        unsigned char byte = buffer->data[i];
        byte_counts[byte]++;

        i++;
    }

    for (int i = 0; i < 256; i++)
    {
        printf("Byte-value %02X: %d\n", i, byte_counts[i]);
    }

    sem_post(&task2);

    printf("threadB is done 2\n");
    return NULL;
}

错误原因及修复方案

核心错误:指针类型不匹配

main函数中创建线程时,传递的参数是&memory(指向Buffer指针的指针,即Buffer**类型),但线程函数里直接将其强转为Buffer*,导致后续访问buffer->size或buffer->data时,实际访问的是错误内存地址,最终触发段错误。

修复:创建线程时直接传递memory(Buffer*类型),而非&memory。

次要问题及修复

  1. 文件打开失败后未终止线程:若文件打开失败,后续的fread、fclose会访问空指针,需在perror后退出线程,同时触发信号量避免线程B无限等待。
  2. fread参数错误:原代码中&buffer->data多余,数组名本身就是首地址,传递buffer->data即可。
  3. 冗余语法问题:thread_B中int i=0;;多了一个分号,已去除。

修复后的完整代码

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#define BUFFER_SIZE 4096
typedef struct _Buffer
{
    int size;
    char data[BUFFER_SIZE];
} Buffer;

sem_t task1, task2;

void *thread_A(void *arg);
void *thread_B(void *arg);
int main(int argc, char *argv[])
{
    
    Buffer *memory = malloc(sizeof(Buffer));
    if (!memory) {
        perror("malloc failed");
        exit(1);
    }

    sem_init(&task1, 0, 0);
    sem_init(&task2, 0, 0);

    pthread_t thread_A_id;
    pthread_t thread_B_id;

    // 修复:传递正确的Buffer*类型参数
    pthread_create(&thread_A_id, NULL, &thread_A, memory);
    pthread_create(&thread_B_id, NULL, &thread_B, memory);
    
    if (pthread_join(thread_A_id, NULL) != 0)
    {
        perror("Error joining thread A");
        exit(1);
    }

    if (pthread_join(thread_B_id, NULL) != 0)
    {
        perror("Error joining thread B");
        exit(1);
    }

    sem_destroy(&task1);
    sem_destroy(&task2);
    free(memory);
    return 0;
}

void *thread_A(void *arg)
{
    Buffer *buffer = (Buffer*) arg;

    FILE *pdf_file = fopen("file.pdf", "rb");
    if (pdf_file == NULL)
    {
        perror("Can not open the file");
        sem_post(&task1); // 触发信号量,避免线程B阻塞
        sem_wait(&task2);
        return NULL;
    }

    printf("size of struct %ld\n", sizeof(Buffer));
    // 修复:传递数组首地址给fread
    buffer->size = fread(buffer->data, sizeof(char), BUFFER_SIZE, pdf_file);

    fclose(pdf_file);

    sem_post(&task1); 
   
    sem_wait(&task2);
    printf("A is out\n");
    return NULL;
}

void *thread_B(void *arg)
{
    printf("IAM IN TREAD B\n");
    Buffer *buffer = (Buffer*) arg;
    
    sem_wait(&task1);
    int i=0;

    int byte_counts[256] = {0};
    // 改用for循环,逻辑更清晰,避免size为负时的无限循环
    for (i = 0; i < buffer->size; i++) {
        unsigned char byte = buffer->data[i];
        byte_counts[byte]++;
    }

    for (int j = 0; j < 256; j++)
    {
        printf("Byte-value %02X: %d\n", j, byte_counts[j]);
    }

    sem_post(&task2);

    printf("threadB is done 2\n");
    return NULL;
}

额外优化说明

  • 增加malloc失败检查,避免空指针问题。
  • 调用sem_destroy销毁信号量,符合资源释放规范。
  • 将thread_B中的while循环改为for循环,逻辑更健壮。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 00:55:34