Gab*_*iMe 9 c++ multithreading visual-c++ c++11 visual-studio-2013
简单的多线程c ++ 11程序,其中所有线程在紧密循环中锁定相同的互斥锁.
当它使用8个线程(作为逻辑cpus的数量)时,它可以达到500万次/秒
但只添加一个额外的线程 - 性能下降到200,000 /秒!
编辑:
在g ++ 4.8.2(ubuntu x64)下:即使有100个线程也没有性能下降!(并且是性能的两倍以上,但这是另一个故事) - 所以这确实是VC++互斥实现的特定问题
我使用以下代码(Windows 7 x64)复制它:
#include <chrono>
#include <thread>
#include <memory>
#include <mutex>
#include <atomic>
#include <sstream>
#include <iostream>
using namespace std::chrono;
void thread_loop(std::mutex* mutex, std::atomic_uint64_t* counter)
{
while (true)
{
std::unique_lock<std::mutex> ul(*mutex);
counter->operator++();
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int threads = 9;
std::mutex mutex;
std::atomic_uint64_t counter = 0;
std::cout << "Starting " << threads << " threads.." << std::endl;
for (int i = 0; i < threads; ++i)
new std::thread(&thread_loop, &mutex, &counter);
std::cout << "Started " << threads << " threads.." << std::endl;
while (1)
{
counter = 0;
std::this_thread::sleep_for(seconds(1));
std::cout << "Counter = " << counter.load() << std::endl;
}
}
Run Code Online (Sandbox Code Playgroud)
VS 2013剖析器告诉我,大部分时间(95.7%)都是在紧密循环中浪费的(rtlocks.cpp中的第697行):
while (IsBlocked() & & spinWait._SpinOnce())
{
//_YieldProcessor is called inside _SpinOnce
}
Run Code Online (Sandbox Code Playgroud)
可能是什么原因?如何改进?
操作系统:Windows 7 x64
CPU:i7 3770 4核(x2超线程)
使用8个线程,您的代码正在旋转,但是在没有CPU必须在线程丢失其时间片之前挂起线程的情况下获取锁定.
随着您添加越来越多的线程,争用级别会增加,因此线程无法在其时间片内获取锁定.当发生这种情况时,线程被挂起并且上下文开关发生在另一个线程中,CPU将检查该线程是否可以被唤醒.
所有这些切换,挂起和唤醒都需要从用户模式转换到内核模式,这是一项昂贵的操作,因此性能会受到很大影响.
要改进一些事情,要么减少争用锁定的线程数量,要么增加可用内核数量.在您的示例中,您使用的是std::atomic数字,因此您无需锁定以便对其进行调用++,因为它已经是线程安全的.
互斥锁给每个线程之间的竞争,无论如何,但是如果您尝试使用多个线程比你有核心,即使他们已经准备好,不是所有的人都能同时运行,因此他们将需要保持停止和启动 - 已知作为上下文切换.
您可以"解决"这个问题的唯一方法是使用更少的线程或获得更多内核.