I would change this to a map/reduce problem.
1) Have a set of `N` mappers.
Each mapper calculates the value for a range.
Then saves the value for use by the reducer.
2) Reducer waits for all mappers to finish
Then calculates a result based on the value generated
by the mappers.
Using this technique you don't need any data locks. You just need a way to know when all the mappers have finished working.
// Sort of pseudo code.
int fact(int n) {
int partitions = calculateNumberOfPartitions(n);
int worker = calculateNumberOfWorkers(n);
std::vector<boost::multiprecision::cpp_int> data(partitions);
boost::multiprecision::cpp_int result;
std::vector<std::function<void()> jobs;
// Calculate all factorial for all the partitions.
for(int loop=0;loop < partitions; loop++) {
jobs.push_back([&data, loop, n](){
// Calculate factorial for
// The range indicated by loop.
// place it in data[loop]
});
}
// The first (n-1) workers will finish
// When they do force them to just wait for the last guy.
std::vector<std::condition_variable> wait(worker-1);
for(int loop=0;loop < (worker-1); ++loop) {
jobs.push_back([&wait, loop](){
wait[loop].wait();
});
}
// When the last worker finishes.
// Let him do the reduce job.
jobs.push_back([&data, &result](){
for(auto& val: data) {
result *= val;
}
});
runJobsInParallel(jobs);
// Now you can release the other workers you put to sleep.
}