如何以多线程方式编码位图块?
How can encode bitmap blocks in a multi-threaded fashion?
我正在尝试对位图图像块进行编码并将其保存到内存中(在矢量内部)。一切正常,直到我尝试以多线程方式执行此操作。我不断收到以下错误:
Error C2672 'std::invoke': no matching overloaded function found
Error C2893 Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...) noexcept()'
我的代码是在 main() 中调用的简单屏幕截图 class,这是我尝试进行多线程处理的地方:
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();
};
GDI+ 中有一个锁可以防止两个线程使用相同的图形对象或相同的位图。无论哪个线程先抢到它,另一个都会异常死掉。
参考:GDI+ objects and multithreading
Some GDI+ methods return ObjectBusy if a thread attempts to call a
method while another thread is executing a method on the same object.
Do not try to synchronize access to an object based on the ObjectBusy
return value.
相反,每次访问成员或调用对象的方法时,将调用置于临界区内,或使用其他一些标准同步技术。
我正在尝试对位图图像块进行编码并将其保存到内存中(在矢量内部)。一切正常,直到我尝试以多线程方式执行此操作。我不断收到以下错误:
Error C2672 'std::invoke': no matching overloaded function found
Error C2893 Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...) noexcept()'
我的代码是在 main() 中调用的简单屏幕截图 class,这是我尝试进行多线程处理的地方:
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();
};
GDI+ 中有一个锁可以防止两个线程使用相同的图形对象或相同的位图。无论哪个线程先抢到它,另一个都会异常死掉。
参考:GDI+ objects and multithreading
Some GDI+ methods return ObjectBusy if a thread attempts to call a method while another thread is executing a method on the same object. Do not try to synchronize access to an object based on the ObjectBusy return value.
相反,每次访问成员或调用对象的方法时,将调用置于临界区内,或使用其他一些标准同步技术。