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

双线程复制图片因二维数组区间错误引发段错误,求修正方案

解决多线程复制图片的段错误问题

你的段错误根源有两个核心问题:

  1. 原interval函数是按**总像素数(一维)**拆分区间,但create_image里错误地把这个一维区间同时当成了二维坐标的x和y范围,导致访问图片数组时越界(比如当区间值超过图片的宽度/高度时,i或j会超出图片的行列范围)。
  2. 你用std::lock_guard把整个复制循环锁住了,这等于所有线程串行执行,完全失去了多线程的意义。

下面是修正后的完整方案:

1. 重新设计区间生成逻辑(按行拆分)

图片是二维结构,最容易并行的方式是按行拆分:每个线程负责处理连续的若干行,这样不需要处理复杂的二维坐标转换,也不会越界。修改区间生成函数,让它生成行的起始和结束索引:

std::vector<int> interval_rows(int total_rows, int n_threads) {
    std::vector<int> intervallum;
    int rows_per_thread = total_rows / n_threads;
    int remainder = total_rows % n_threads;
    int current_start = 0;
    intervallum.push_back(current_start);
    
    for (int i = 0; i < n_threads; i++) {
        int current_end = current_start + rows_per_thread;
        // 把剩余的行分配给最后一个线程
        if (i == n_threads - 1) {
            current_end += remainder;
        }
        intervallum.push_back(current_end);
        current_start = current_end;
    }
    return intervallum;
}

2. 修改线程任务函数(处理指定行范围)

调整create_image,让它只处理start_row到end_row之间的行,每个行里遍历所有列。同时去掉不必要的mutex,因为每个线程处理的行是独立的,没有共享资源竞争:

void create_image(png::image<png::rgb_pixel>& image, png::image<png::rgb_pixel>& new_image, int start_row, int end_row) {
    int width = image.get_width();
    for (int i = start_row; i < end_row; i++) {
        for (int j = 0; j < width; j++) {
            new_image[i][j] = image[i][j]; // 直接赋值像素,简化代码
        }
    }
}

3. 修正main函数的调用逻辑

用总行数来生成区间,正确启动线程,并且不需要单独再调用一次create_image(线程已经覆盖了所有行):

int main() {
    png::image<png::rgb_pixel> png_image("mandel.png");
    int image_width = png_image.get_width();
    int image_height = png_image.get_height();
    png::image<png::rgb_pixel> new_image(image_width, image_height);
    
    time_t start_time, end_time;
    time(&start_time);
    
    const int thread_count = 2;
    std::vector<std::thread> threads;
    std::vector<int> row_intervals = interval_rows(image_height, thread_count);
    
    // 启动所有线程
    for (int i = 0; i < thread_count; i++) {
        threads.emplace_back(create_image, std::ref(png_image), std::ref(new_image), row_intervals[i], row_intervals[i+1]);
    }
    
    // 等待所有线程完成
    for (auto& t : threads) {
        t.join();
    }
    
    new_image.write("test.png");
    time(&end_time);
    std::cout << "耗时: " << difftime(end_time, start_time) << " 秒" << std::endl; // 修正时间计算逻辑
    
    return 0;
}

额外的优化说明

  • 直接赋值new_image[i][j] = image[i][j]比单独赋值rgb三个通道更简洁高效。
  • 修正了时间计算的错误:原来的start - end会得到负数,改用difftime(end_time, start_time)来计算实际耗时。
  • 去掉mutex后,线程才能真正并行执行,提升复制效率。

这样修改后,就不会出现段错误,同时真正利用多线程并行处理图片复制了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:19:05