Hi there!
I tried to study parallelism with std::thread. I read a lot of topics and examples on this theme, but I just can’t implement this in my program.
For starters, description:
Since creating and deleting threads is a labor-intensive process for the CPU, I decided to create a vector with a given number of threads in Level1.cpp:
Level1.h
class Level1 : public cocos2d::Layer
{
public:
static cocos2d::Scene* createScene();
virtual bool init();
CREATE_FUNC(Level1);
void update(float dt) override;
private:
// ... (declaration of variables)
std::vector<std::thread> threadsPool;
std::mutex mtx;
};
in Level1.cpp
bool Level1::init()
{
if (!Layer::init())
{
return false;
}
// ... initializations
int numThreads = std::thread::hardware_concurrency();
threadsPool.resize(numThreads);
this->scheduleUpdate();
return true;
}
void Level1::update(float dt)
{
// ... other calculations
vai->vehicleAIMovement(dt, vehiclePlayerPosition, vehicleAIList, WayPointsList, it, threadsPool, mtx);
}
(vai - object of VehicleAI class)
VehicleAI class class has 3 functions:
vehicleAIMovement() - function called from Level1::update(float dt)
trackingTrajectory() - function called from vehicleAIMovement()
trackingOtherVehicles() - function called from trackingTrajectory()
so in VehicleAI.cpp
float VehicleAI::trackingTrajectory(cocos2d::Vec2 vehiclePlayerPosition, std::vector<std::shared_ptr<VehicleAI>> vehicleAIList, int iterator, float V, float dt, std::vector<std::thread>& threadsPool, std::mutex& mtx)
{
// ... many many calculations
int iterator1 = 0;
// check every object in the list
while (vehicleAIList.size() > iterator1)
{
// except itself
if (iterator1 != iterator)
{
auto otherAIVehicle = vehicleAIList.at(iterator1);
for (auto&& thread : threadsPool)
{
if (thread.joinable())
{
continue;
}
else
{
thread = std::thread([=, &boolStopVehicle, &allVehiclesOnCrossroadStopped, &distNearestVehicle] {trackingOtherVehicles(otherAIVehicle, FM1, RM1, FR1, FL1, RR1, RL1, iterator1, F1, V1, W1, L1, minStoppingDistance, decelerationDistance, STP, std::ref(boolStopVehicle), std::ref(allVehiclesOnCrossroadStopped), std::ref(distNearestVehicle)); });
}
}
}
iterator1++;
}
}
trackingOtherVehicles() function should overwrite the “boolStopVehicle” variable, and a few more.
In this form, the code does not work correctly: the function ceases to be called when all threads initially receive their task.
(By the way, the number of threads is much smaller than the size of the “vehicleAIList” vector)
Trying to solve the issue of thread congestion, I came to this conclusion:
int iterator1 = 0;
// check every object in the list
while (vehicleAIList.size() > iterator1)
{
// except itself
if (iterator1 != iterator)
{
auto otherAIVehicle = vehicleAIList.at(iterator1);
bool allThreadsRunning = true;
while (allThreadsRunning)
{
for (auto&& thread : threadsPool)
{
if (thread.joinable())
{
if (allThreadsRunning)
{
thread.join();
}
else
{
continue;
}
}
else
{
std::lock_guard<std::mutex> lock(mtx);
thread = std::thread([=, &boolStopVehicle, &allVehiclesOnCrossroadStopped, &distNearestVehicle] {trackingOtherVehicles(otherAIVehicle, FM1, RM1, FR1, FL1, RR1, RL1, iterator1, F1, V1, W1, L1, minStoppingDistance, decelerationDistance, STP, std::ref(boolStopVehicle), std::ref(allVehiclesOnCrossroadStopped), std::ref(distNearestVehicle)); });
allThreadsRunning = false;
}
}
}
}
iterator1++;
}
But it still doesn’t work correctly and does not provide any parallelization benefits. The program starts to slow down even more.
It’s obvious that I’m doing something wrong, but I don’t understand how to handle it.
I hope for the help of the guru)