首页 > 解决方案 > C ++:使用多个线程修改相同的指针

问题描述

我正在尝试处理图像的实验,其中我正在修改每个像素的颜色。我尝试使用“桶”来实现我的代码,其中我将图像划分为更小的区域——每个区域都接收一个专用线程来处理图像。

就我而言,我并不关心多个线程是否试图修改同一个资源,事实上,这似乎是重点。理论上,线程应该以像素的形式修改内存中的不同位置。然而,当打印我的结果时,似乎只有第一个任务会迭代 - 导致我认为某种竞争条件正在发生。

下面的函数管理每个任务的创建,并为其提供起始坐标和跨度以进行操作。我相信这工作正常,但它只是为了上下文:

Image* 
CCManager::CCAsync(uint8_t bucketSize, Image* source, 
                                        const std::vector<float>& correction)
{
    Image* newImg = new Image(); // This will contain our end result
    newImg->resize(source->width(), source->height());

    assert(buckets > 0);

    // Now compute the width and height each bucket will render.
    uint32_t width;
    uint32_t height;

    if(buckets == 2)    // Each bucket takes a vertical rectangle
    {
        width = source->xSize()/2;
        height = source->ySize();
    }
    else
    {
        // Set width and height to produce square grids (powers of 2)
        // *** Not shown for Brevity ***
    }

    std::vector<std::thread> tasks; // The threads we are managing

    // These coordinates will be fed as starting locations for each task
    uint32_t startX = 0;
    uint32_t startY = 0;
    uint8_t  tasksFinished = 0; 

    for(int i = 1; i <= buckets; ++i)
    {   

        // Create a new task with a region for operation
        tasks.emplace_back(std::thread(&CCManager::applyCCTask,this, startX, startY,
                                       width, height, source, newImg, correction));

        // No iteration is required for 1 bucket, simply paint the whole image
        if(buckets == 1){break;}

        // **** I REMOVED PART OF THE CODE THAT SHOWS WHERE EXPONENT
        // IS DEFINED AND DETERMINED FOR BREVITY
        // Reached last column, start a new row
        if(i % exponent == 0)
        {
            startX = 0;
            startY+= height;
        }
        // Keep incrementing horizontally
        else
        {
            startX+= width;
        }
    }

    while(tasksFinished < buckets)
    {
        // Join with whichever tasks finished
        for(int i = 0; i < buckets; ++i)
        {
            if(tasks[i].joinable())
            {
                tasks[i].join();
                tasksFinished++;
            }
        }
    }
    tasks.clear();

    return newImg;
}

为每个任务提供了新的和源图像指针后,它们就开始起作用了。

下面的函数检索每个像素中的颜色,并调用一个相应地应用校正的方法。

void 
CCManager::applyCCTask(uint32_t x, uint32_t y, uint32_t width, uint32_t height,
                              Image* source, Image* newImg,
                              const std::vector<float>& correction)
{
    // ** THIS ACTUALLY PRINTS THE CORRECT COORDINATES AND REGION SPAN
    // ** FOR EACH THREAD
    printf("Task renders @ (%i,%i) with %i x %i box\n", x,y,width,height);
    assert(source);
    assert(newImg);

    for (; x < width; ++x )
    {
        for (; y < height; ++y)
        {
            Byte4 pixel = source->pixel (x, y);
            Color color = pixel.color;

            printf("Before correction: Pixel(%i,%i) color [%i,%i,%i]\n",x,y, pixel.color[0], pixel.color[1], pixel.color[2]);
                Color correctedColor= addCorrectionToColor( color, correction);

            Byte4* newPixel= &newImg->pixel( x, y );

            newPixel->color[0] = correctedColor[0];
            newPixel->color[1] = correctedColor[1];
            newPixel->color[2] = correctedColor[2];  

            printf("After correction: Pixel(%i,%i) color [%i,%i,%i]\n",x,y, newImg->pixel( x, y ).color[0], newImg->pixel( x, y ).color[1], newImg->pixel( x, y ).color[2]);
        }
    }

    printf("Task Finished!\n");
}

使用显示的代码,所有任务最终都会打印带有其操作区域的起始消息,但在嵌套循环内,“之前”和“之后”消息似乎只从一个任务打印。

为什么我不允许从多个线程修改相同的图像,即使每个线程修改的实际像素数据不同?我是否可以避免在不添加诸如互斥锁之类的资源锁的情况下,这个实验的重点是让每个线程独立运行而不受任何阻碍。

标签: c++multithreadingconcurrencyrace-condition

解决方案


推荐阅读