Как можно кодировать блоки растровых изображений в многопоточном режиме? - PullRequest
0 голосов
/ 03 августа 2020

Я пытаюсь закодировать блок растрового изображения и сохранить его в памяти (внутри вектора). Все работает нормально, пока я не попробую сделать это в многопоточном режиме. Я продолжаю получать следующие ошибки:

Ошибка C2672 'std :: invoke': не найдено совпадающей перегруженной функции

Ошибка C2893 Не удалось специализировать шаблон функции ' unknown-type std :: invoke (_Callable &&, _ Types && ...) noexcept () '

Мой код - это простой класс для съемки экрана, вызываемый внутри main (), здесь я пробую для многопоточности:

bool Screenshot::threadfunc(Gdiplus::Bitmap* bmp, int i, int j, int x, int y, int bw, int bh, std::vector<std::vector< std::vector<BYTE> >> blocksBmpBytesMatrix, std::string dataFormat)
{
    Gdiplus::Bitmap* tile = bmp->Clone(x, y, bw, bh, PixelFormat24bppRGB);

    // write to IStream
    IStream* istream = nullptr;
    CreateStreamOnHGlobal(NULL, TRUE, &istream);

    // define encoding
    CLSID clsid;
    CLSIDFromString(L"{557cf400-1a04-11d3-9a73-0000f81ef32e}", &clsid);

    Gdiplus::Status status = tile->Save(istream, &clsid, NULL);
    if (status != Gdiplus::Status::Ok)
        std::wcout << "ERROR" << std::endl;
    return false;

    // get memory handle associated with istream
    HGLOBAL hg = NULL;
    GetHGlobalFromStream(istream, &hg);

    // copy IStream to buffer
    int bufsize = GlobalSize(hg);
    blocksBmpBytesMatrix[i][j].resize(bufsize);

    // lock & unlock memory
    LPVOID pimage = GlobalLock(hg);
    memcpy(&blocksBmpBytesMatrix[i][j][0], pimage, bufsize);
    GlobalUnlock(hg);
    istream->Release();
    return true;
};

bool Screenshot::divideIntoBlocks(HWND chwnd, int screenshotId, RECT rcMonitors, int blockHeight, int blockWidth)
{
    Gdiplus::Bitmap bmp(hbwindow, nullptr);
    int nrows = height / blockHeight + 1 * int((height % blockHeight) != 0);
    int ncols = width / blockWidth + 1 * int((width % blockWidth) != 0);

    for (int i = 0; i < nrows; i++)
    {
        for (int j = 0; j < ncols; j++)
        {
            // compute block coordinates and dimensions
            int x = j * blockWidth;
            int y = i * blockHeight;
            int bw = ((x + blockWidth) > width) * (width % blockWidth) + ((x + blockWidth) <= width) * blockWidth;
            int bh = ((y + blockHeight) > height) * (height % blockHeight) + ((y + blockHeight) <= height) * blockHeight;

            // append to vecs
            blocksInfo.push_back({ i, j, x, y, bw, bh });
        }
    }

    std::vector<std::thread*> pool(nrows * ncols);
    for (auto& ij : blocksInfo)
    {
        std::cout << ij.size() << " : " << ij[0] << "," << ij[1] << "," << ij[2] << "," << ij[3] << "," << ij[4] << "," << ij[5] << std::endl;
        std::thread t(&Screenshot::threadfunc, &bmp, ij[0], ij[1], ij[2], ij[3], ij[4], ij[5], this->blockPngBytesMatrix, "png");
        pool.push_back(&t);
    }
    for (auto& t : pool) { t->join(); }

    return true;
}

любая идея, что я здесь делаю не так? или если я могу (как я могу) сделать это многопоточное кодирование?

Изменить: это Screenshot.h

class Screenshot
{
    public:
        // screenshot dimensions and coordinates
        int width, height;
        int screenx, screeny;

        // inti coordinates and dimensions vectors
        std::vector< std::vector<int>> blocksInfo;

        // init data matrices
        std::vector<std::vector< std::vector<BYTE> >> blocksPngBytesMatrix;

        // init screenshot bmp and hbmp 
        HBITMAP hbwindow;
        BITMAPINFOHEADER bi; 

        // init handle for display contexts
        HDC hwindowDC;
        HDC hwindowCompatibleDC;

        // constructor
        Screenshot(RECT, int, int);

        // funcs
        BITMAPINFOHEADER createBitmapHeader(int, int);
        bool capture();
        bool divideIntoBlocks(HWND, int, RECT, int, int);
        bool saveToMemory(Gdiplus::Bitmap*, std::vector<BYTE>&, std::string);
        bool threadfunc(Gdiplus::Bitmap*, int, int, int, int, int, int, std::vector<std::vector< std::vector<BYTE> >>, std::string);

        // deconstructor
        ~Screenshot();
};

1 Ответ

0 голосов
/ 04 августа 2020

Внутри GDI + есть блокировка, которая не позволяет двум потокам использовать один и тот же объект Graphics или одно и то же Bitmap. Какой бы поток ни добирался до него первым, захватывает блокировку, другой будет d ie с исключением.

Обратитесь: Объекты GDI + и многопоточность

И Синхронизация потоков также указывает:

Некоторые методы GDI + возвращают ObjectBusy, если поток пытается вызвать метод, в то время как другой поток выполняет метод для того же объекта. Не пытайтесь синхронизировать доступ к объекту на основе возвращаемого значения ObjectBusy.

Вместо этого каждый раз, когда вы обращаетесь к члену или вызываете метод объекта, помещайте вызов внутри критического раздел, или используйте другой стандартный метод синхронизации.

...