Cpp - jgoffeney/Cesium4Unreal GitHub Wiki
Threads were introduced in C++11. When creating the thread you pass in a static function or lambda, start processing and then use join() to wait for completion. Calling detach() after creation will separate the execution from the thread object.
std::vector<std::thread> threadList(numThreads);
// Create and start threads running the function
for(unsigned int tIdx = 0; tIdx < threadList.size(); tIdx++)
{
threadList[tIdx] = std::thread(function, param0, param1, ..., paramN);
}
// Wait for threads to complete
for(unsigned int tIdx = 0; tIdx < threadList.size(); tIdx++)
{
threadList[tIdx].join();
}
Since C++17 the C++ spec has included definitions for parallel processing.
Included in std::execution, policies are passed to functions to indicate how the data should be processed. It is designed to be extendable to target different architectures.
- sequenced_policy seq : forces an algorithm to be run sequentially (not in parallel)
- parallel_policy par : indicates an algorithm can be run in the calling thread or in a separate thread created by the library for parallel execution
- parallel_unsequenced_policy par_unseq : indicates an algorithm may be parallelized, vectorized or migrated across threads. Element accesses are unsequenced within and across threads.
- unsequenced_policy unseq : indicates an algorithm can be run on the same thread but vectorized via special instructions
The std::transform function can be used as a basis for running parallel algorithms.
Define a base function. This is defined as static.
std::vector<float> inputVector(10000, 2.0);
std::vector<float> outputVector(10000);
// Double the value in the input
std::transform(std::execution::par, inputVector.begin(), inputVector.end(),
outputVector.begin(), [](float v){return v * 2.0}
);
glm::dvec3 GeospatialFunctions::_convertXYZToLLAd(const glm::mat4& transformMatrix,
const glm::vec3& xyzPosition) {
try {
glm::dvec3 llaPosition;
glm::dvec4 xyzwPosition(xyzPosition, 1.0);
glm::dvec4 updatedXyz = LinearAlgebraFunctions::MatrixVectorMultiply(transformMatrix,
xyzwPosition);
const double a = 6378137.0; // WGS 84 ellipsoid semi-major axis
const double b = 6356752.3142451793f; // WGS 84 ellipsoid semi-minor axis
const double ecc1Sqrd = 0.00669438f; // WGS 84 ellipsoid first eccentricity squared
const double ecc2Sqrd = 0.006739497f; // WGS 84 ellipsoid second eccentricity squared
llaPosition.x = atan2(updatedXyz.y, updatedXyz.x) * RAD2DEG;
double p = sqrt(updatedXyz.x * updatedXyz.x + updatedXyz.y * updatedXyz.y);
double theta = atan2(updatedXyz.z * a, p * b);
double sinTheta = sin(theta);
double cosTheta = cos(theta);
double latY = updatedXyz.z + ecc2Sqrd * b * sinTheta * sinTheta * sinTheta;
double latX = p - ecc1Sqrd * a * cosTheta * cosTheta * cosTheta;
//Compute latitude in radians
double latRad = atan2(latY, latX);
llaPosition.y = latRad * RAD2DEG;
double sinLat = sin(latRad);
double N = a / sqrt(1.0f - ecc1Sqrd * sinLat * sinLat);
// Compute elevation
llaPosition.z = (p / cos(latRad)) - N;
return llaPosition;
}
catch (const Exception& e)
{
throw Exception("GeospatialFunctions", __FUNCTION__, __LINE__, e);
}
catch (const std::exception& e)
{
throw Exception("GeospatialFunctions", __FUNCTION__, __LINE__, e.what());
}
catch (...)
{
throw Exception("GeospatialFunctions", __FUNCTION__, __LINE__);
}
}
Run the function in parallel via std::transform. Note the '&' in the brackets. This indicates the lambda function parameter can use variable external to its body.
void GeospatialFunctions::ConvertXYZToLLA(const glm::mat4& transformMatrix,
const std::vector<glm::vec3>& xyzPositions, std::vector<glm::dvec3>& llaPositions) {
try {
// This is essentially a parallel foreach statement based on the xzyPositions vector
std::transform(std::execution::par, xyzPositions.begin(), xyzPositions.end(),
llaPositions.begin(), [&](const glm::vec3& xyz) {
return _convertXYZToLLAd(transformMatrix, xyz);
});
}
catch (const Exception& e)
{
throw Exception("Glb2RasterFunctions", __FUNCTION__, __LINE__, e);
}
catch (const std::exception& e)
{
throw Exception("Glb2RasterFunctions", __FUNCTION__, __LINE__, e.what());
}
catch (...)
{
throw Exception("Glb2RasterFunctions", __FUNCTION__, __LINE__);
}
}