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

多线程程序异常:前若干线程被跳过,最后一线程处理多数任务

多线程任务拆分异常:前序线程被跳过,最后一线程处理大部分任务

我花了好几个小时都没找出问题所在。我写了一个从0到9计数的程序(目标是实现1到10,可调整数组填充逻辑),预期用多线程实现,并根据指定线程数动态拆分任务数组。但实际运行出现异常:前2个线程直接被跳过,最后一个线程处理了大部分任务。我怀疑是创建线程的for循环出了问题,调整过第57行的循环索引,虽有局部变化,但核心问题仍未解决。

程序代码

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

typedef struct
{
    int *array;
    int batch;
    int start;
    int end;
} Parameter;

void *method(void *p)
{
    Parameter *param = (Parameter *)p;

    for (int i = param->start; i < param->end; i++)
    {
        printf("Start:%d\tEnd:%d\tIndex:%d\tValue:%d\n", param->start, param->end, i,param->array[i]);
        
    }
}

int main(int argc, char **argv)
{
    // 获取用户输入
    int array_length = atoi(argv[1]);
    int batches = atoi(argv[2]);

    printf("User specified Array:%d\tBatch:%d\n", array_length, batches);

    // 创建数组
    int *array = (int *)calloc(array_length, sizeof(int));
    
    // 填充数据
    for (int i = 0; i < array_length; i++)
    {
        array[i] = i;
    }

    // 确定批处理大小
    int batch_size = array_length / batches;
    int remainder = array_length % batches;

    printf("%d\n", batch_size);
    printf("%d\n", remainder);

    int start = 0;
    int end = 0;
    int index =0;

    // 参数列表
    Parameter *param = (Parameter *)calloc(batches, sizeof(Parameter));
    pthread_t *threads = (pthread_t *)calloc(batches, sizeof(pthread_t));

    // 遍历每个批处理
    for (int i = 0; i < batches; i++)
    {
        printf("\n\nBatch number -> %d\n", i);
        end = start + batch_size;
        if (remainder > 0)
        {
            remainder --;
            end ++;
        }

        // 填充参数
        param[i].array = array;
        param[i].end = end;
        param[i].start = start;
        param[i].batch = i;

        // 创建线程
        pthread_create(threads + index, NULL, method, (void *)&param[i]);
        index++;
        start = end;
    }

    for (int i = 0; i < batches; i++)
    {
        pthread_join(threads[i], NULL);
    }

    free(param);
    free(threads);
    free(array);

    return 0;
}

问题分析

核心问题是线程参数的竞态条件:

  • 你在pthread_create中传递的是&param[i],也就是param数组中当前元素的地址。但主线程的for循环会快速执行,在新线程还未读取参数内容前,就已经修改了param[i]的后续元素(甚至当i递增后,循环会覆盖下一个param元素)。
  • 当线程真正开始执行时,读取到的param内容已经被主线程的后续循环修改,导致多个线程拿到了最后一个线程的参数,出现前序线程被“跳过”、最后一线程处理大量任务的现象。

额外的小问题:

  1. 线程函数method没有返回值,不符合pthread要求的void*(*)(void*)函数签名,需补充return NULL;。
  2. 数组填充逻辑是从0开始,若目标是1到10,可改为array[i] = i+1;。

修复方案

方案:为每个线程分配独立参数内存

不再复用param数组的元素,而是为每个线程单独分配Parameter结构体内存,确保主线程的循环不会干扰线程已获取的参数:

修改主线程创建线程的代码段

// 遍历每个批处理
for (int i = 0; i < batches; i++)
{
    printf("\n\nBatch number -> %d\n", i);
    end = start + batch_size;
    if (remainder > 0)
    {
        remainder --;
        end ++;
    }

    // 为当前线程分配独立的参数内存
    Parameter *thread_param = (Parameter *)malloc(sizeof(Parameter));
    thread_param->array = array;
    thread_param->end = end;
    thread_param->start = start;
    thread_param->batch = i;

    // 创建线程,直接使用i作为threads数组索引,无需额外index变量
    pthread_create(&threads[i], NULL, method, (void *)thread_param);
    start = end;
}

修改线程函数,释放参数内存

void *method(void *p)
{
    Parameter *param = (Parameter *)p;

    for (int i = param->start; i < param->end; i++)
    {
        printf("Start:%d\tEnd:%d\tIndex:%d\tValue:%d\n", param->start, param->end, i,param->array[i]);
        
    }
    // 释放为当前线程分配的参数内存
    free(param);
    // 补充符合要求的返回值
    return NULL;
}

额外优化

原代码中的index变量完全多余,直接用循环变量i作为threads数组的索引即可,简化逻辑。

验证效果

运行./your_program 10 3时,三个线程会正确拆分任务:

  • 线程0:处理索引0-4(共5个元素,因为余数1分配给第一个线程)
  • 线程1:处理索引4-7(共3个元素)
  • 线程2:处理索引7-10(共3个元素)

每个线程都会输出对应区间的内容,不会出现前序线程被跳过的异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 01:45:30