双线程复制图片因二维数组区间错误引发段错误,求修正方案
解决多线程复制图片的段错误问题
你的段错误根源有两个核心问题:
- 原
interval函数是按**总像素数(一维)**拆分区间,但create_image里错误地把这个一维区间同时当成了二维坐标的x和y范围,导致访问图片数组时越界(比如当区间值超过图片的宽度/高度时,i或j会超出图片的行列范围)。 - 你用
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
相关产品推荐
相关产品推荐

