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

C语言pthreads未调用或无故多次调用的多线程素数计算问题

问题引发原因

  • 线程参数使用了栈临时变量地址:创建线程的循环内定义的struct ipp_args args是栈局部变量,每次循环迭代都会复用同一块内存并覆盖原有值。pthread_create仅传递参数地址、不拷贝参数内容,线程启动后读取参数时,栈上的值早已被后续循环修改,最终所有线程都可能读取到最后一次循环的id=3,表现为多个线程输出相同ID、其余ID无输出。
  • 全局计数存在数据竞争:多个线程同时对全局变量count执行自增操作,该操作不是原子指令,会出现读写冲突导致计数丢失,也是素数统计结果每次不一致的原因。

修复方案

具体修改点

  1. 用主函数栈数组存储每个线程的独立参数,保证参数内容在线程运行期间不会被覆盖
  2. 引入互斥锁保护count的自增操作,避免数据竞争
  3. 补充原代码中未使用的start参数逻辑,适配自定义起始区间的需求

编译命令:gcc primes.c -o primes -lpthread -lm

修复后完整代码

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

#define THREADS_NUM 4

struct ipp_args{
    int id;     // ID of the thread
    int start;  // 区间起始值
    int stop;   // Max number to test
};

void *prime_checker(void*);

pthread_t threads[THREADS_NUM];
struct ipp_args args_arr[THREADS_NUM]; // 存储每个线程的独立参数
pthread_mutex_t count_mutex = PTHREAD_MUTEX_INITIALIZER; // 计数锁
int count = 0;

int main(int argc, char const *argv[]) {
    int start, end;

    if (argc == 1) {
        start = 2;
        end = 100;
    } else if (argc == 3) {
        start = atoi(argv[1]);
        end = atoi(argv[2]);
    } else {
        printf("Usage:\n\tprimes <from> <to>\n");
        exit(1);
    }
    if (start < 2) start = 2;
    
    // Launch threads
    for (int thread_id = 0; thread_id < THREADS_NUM; ++thread_id) {
        args_arr[thread_id].id = thread_id;
        args_arr[thread_id].start = start;
        args_arr[thread_id].stop = end;
        
        printf("[MAIN] Starting T_%d\n", thread_id);
        int error = pthread_create(&threads[thread_id], NULL, prime_checker, (void*)&args_arr[thread_id]);
        if (error) {
            printf("[MAIN] Cannot create thread %d\n", thread_id);
            exit(3);
        }
    }

    // Join threads
    for (int thread_id = 0; thread_id < THREADS_NUM; thread_id++) {
        printf("[MAIN] Joining T_%d\n", thread_id);
        int error = pthread_join(threads[thread_id], NULL);
        if (error) {
            printf("[MAIN] Cannot join thread %d\n", thread_id);
            exit(4);
        }
    }

    printf("%d primes found\n", count);

    pthread_exit(NULL);
    return 0;
}

void *prime_checker(void *_args) {
    struct ipp_args *args = _args;
    int id = args->id;
    int start = args->start;
    int stop = args->stop;
    printf("[T_%d] Started!\n", id);

    // 计算当前线程第一个要检查的数,对齐到start
    int n = start + id;
    if (n < 2) n = 2 + id;
    for (; n < stop; n += THREADS_NUM) {
        int limit = sqrt(n);
        bool prime = true;
        for (int i = 2; i <= limit; i++) {
            if (n % i == 0) {
                prime = false;
                break;
            }
        }
        if (prime) {
            pthread_mutex_lock(&count_mutex);
            count++;
            pthread_mutex_unlock(&count_mutex);
        }
    }

    pthread_exit(NULL);
    return NULL;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 11:30:03