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); int valuesPerPart = n+1 / partitions; if (partitions * valuesPerPart <= n) { ++valuesPerPart; } 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, valuesPerPart](){ int low = loop * valuesPerPart; int high = low + valuesPerPart; high = high > n ? n+1 : high; boost::multiprecision::cpp_int part = 1; for(int val = low; val < high; ++val) { part *= val; } data[loop] = part; }); } // 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. }