I am the novice of multithreading, and I want to try to use the 2048*2048 height map texture to generate a set of vertices.
void HeightMap::CalculateVertices(Vector3 vertex_scale, Vector2 texture_scale, int start, int end, GLubyte* data) {
for (unsigned int z = start; z < end; z) {
for (unsigned int x = 0; x < width; x) {
unsigned int offset = z * height x;
vertices[offset] = Vector3(x, data[offset], z) * vertex_scale;
textureCoords[offset] = Vector2(x, z) * texture_scale;
}
}
}
The problem is when I try to add thread to vector, if I add them one by one:
threads.push_back(std::thread([&]
{CalculateVertices(vertex_scale, texture_scale, 0, dataSize, data); }));
threads.push_back(std::thread([&]
{CalculateVertices(vertex_scale, texture_scale, dataSize, dataSize * 2, data); }));
threads.push_back(std::thread([&]
{CalculateVertices(vertex_scale, texture_scale, dataSize * 2, dataSize * 3, data); }));
threads.push_back(std::thread([&]
{CalculateVertices(vertex_scale, texture_scale, dataSize * 3, dataSize * 4, data); }));
Then everything run properly.
But if I use loop to add thread:
for (int i = 0; i < 4; i) {
threads.push_back(std::thread([&]
{CalculateVertices(vertex_scale, texture_scale, dataSize * i, dataSize * (i 1), data); }));
}
, the error occured, it shows the parameter "end" in the function "CalculateVertices" is 2560. Logically, the range should not exceed 2048.
Then I try to do some change, I just calculate the "start" and "end" not in the parameter list:
for (int i = 0; i < 4; i) {
int start = dataSize * i;
int end = dataSize * (i 1);
threads.push_back(std::thread([&]
{CalculateVertices(vertex_scale, texture_scale, dataSize * i, dataSize * (i 1), data); }));
}
, now the out of range problem is fixed, but the result still wrong, it seems only generate half of the vertices.
I am not familiar to multithreading, and this is my first attempt to use multithreading, I want to know the reason of the problem. According to my experience, I just change one-by-one code to loop, the logic should not be different.
CodePudding user response:
The secret is your lazy auto-capture-by reference:
std::thread([&]{ /*...*/ })
This is almost always a bad idea. In this case, you are capturing i
by reference, which means when the thread invokes the lambda, i
might not even exist and will certainly not have the correct value.
At the very least, capture i
by value. In fact, you can probably capture all this stuff by value in this case.
std::thread([=]{ /*...*/ })