对于某些并发程序,不涉及用线程梳理流程问题,只涉及并发运算,那么其实际使用线程不应超过cpu内核数量,否则并不会提高效率。
C++给每个线程实现了单一id,如果将线程设计为不同的使用目的,可通过线程id进行区别。
C++实现了线程数量函数,
const uint32_t hardware_threads = std::thread::hardware_concurrency();
用以确定cpu内核数量,分配最佳线程数量。
每分配一个线程,都会消耗相应的资源,包括内存,cpu算力。
当线程数量等于cpu内核数量,cpu算力效率达到最高,再增加线程数量,只会使得cpu算力下降,因为算力会分出相当部分用于同一内核间线程切换。
所以某些并发算法需要控制实际使用线程数量,而非一味增加线程。
#include
#include
#include
#include
//用于每个线程的累加计算
template <typename Iterator, typename T>
struct accumulateBlock
{
void operator()(Iterator first, Iterator last, T &result)
{
result = std::accumulate(first, last, result);
}
};
//多线程累计计算算法
template <typename Iterator, typename T>
auto parallelAccumulate(Iterator first, Iterator last, T init) -> T
{
uint32_t const length = std::distance(first, last);
if (!length)
{
return init;
}
const uint32_t minPerThread = 25;
const uint32_t maxThreads = (length + minPerThread - 1) / minPerThread;
//取得cpu内核数量,如系统不支持,则为0
const uint32_t hardwareThreads = std::thread::hardware_concurrency();
//取得真正使用的线程数量
const uint32_t numThreads =
std::min(hardwareThreads != 0 ? hardwareThreads : 2, maxThreads);
const uint32_t blockSize = length / numThreads;
//装载每个线程计算结果,用于最后累计
std::vector<T> results(numThreads);
//装载线程容器
std::vector<std::thread> threads(numThreads - 1);
Iterator blockStart = first;
//开启线程进行累计计算
for (uint32_t i = 0; i != (numThreads - 1); ++i)
{
Iterator blockEnd = blockStart;
std::advance(blockEnd, blockSize);
threads[i] = std::thread(accumulateBlock<Iterator, T>(), blockStart,
blockEnd, std::ref(results[i]));
blockStart = blockEnd;
}
//主线程进行最后一块的累计计算
accumulateBlock<Iterator, T>()(blockStart, last, results[numThreads - 1]);
//等待所有线程完成
for (auto &entry : threads)
{
entry.join();
}
return std::accumulate(results.begin(), results.end(), init);
}
auto main(int /*unused*/, char * /*argv*/[]) -> int
{
std::vector<int> test(50);
int cnt = 0;
for (int i = 0; i != 50; ++i)
{
test[i] = i;
cnt += i;
}
auto result = parallelAccumulate(test.begin(), test.end(), 0);
std::cout << result << ' ' << cnt << std::endl;
return 0;
}
有时候我们需要用线程梳理业务逻辑,此时就需要识别每一个线程,使用C++线程id,非常容易。
以下是用于分辨主线程的示例。
#include
#include
std::thread::id masterThread = std::this_thread::get_id();
void doMasterThreadWork();
void doCommonWork();
void someCorePartOfAlgorithm()
{
if (std::this_thread::get_id() == masterThread)
{
doMasterThreadWork();
}
doCommonWork();
}
auto main(int /*unused*/, char * /*argv*/[]) -> int
{
someCorePartOfAlgorithm();
std::thread t(someCorePartOfAlgorithm);
t.join();
return 0;
}
void doMasterThreadWork()
{
std::cout << "master" << std::this_thread::get_id() << std::endl;
}
void doCommonWork()
{
std::cout << "common" << std::this_thread::get_id() << std::endl;
}
设置合适的线程数量,以榨取最大cpu算力,辨别线程id,以梳理业务逻辑。
使用C++线程库,很容易实现。