Windows 8 及更高版本上的 CRITICAL_SECTION 性能似乎变得更差。 (见下图)
测试非常简单:一些并发线程每个执行 300 万次锁定以独占方式访问变量。您可以在问题底部找到 C++ 程序。我在 Windows Vista、Windows 7、Windows 8、Windows 10(x64、VMWare、Intel Core i7-2600 3.40GHz)上运行测试。
结果如下图所示。
X 轴是并发线程数。
Y 轴是以秒为单位的经过时间(越低越好)。
我们可以看到什么:
-
SRWLock
所有平台的性能大致相同
-
CriticalSection
在 Windows 8 及更高版本上,性能相对 SRWL 变得更差
问题是:有人能解释一下为什么 CRITICAL_SECTION 性能在 Win8 及更高版本上变得更差吗?
一些注意事项:
- 真机上的结果几乎相同 - CS 比 Win8 及更高版本上的 std::mutex、std::recursive_mutex 和 SRWL 差得多。但是我没有机会在具有相同 CPU 的不同操作系统上运行测试。
-
std::mutex
Windows Vista 的实现基于CRITICAL_SECTION
,但适用于Win7及更高版本std::mutex
基于 SWRL。对于 MSVS17 和 15 都是正确的(为了确保搜索primitives.h
文件在 MSVC++ 安装并查找stl_critical_section_vista
and stl_critical_section_win7
类)这解释了 Win Vista 和其他操作系统上 std::mutex 性能的差异。
- 正如评论中所说,
std::mutex
是一个包装器,因此相对 SRWL 的一些开销的可能解释可能是包装器代码引入的开销。
#include <chrono>
#include <iostream>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
#include <Windows.h>
const size_t T = 10;
const size_t N = 3000000;
volatile uint64_t var = 0;
const std::string sep = ";";
namespace WinApi
{
class CriticalSection
{
CRITICAL_SECTION cs;
public:
CriticalSection() { InitializeCriticalSection(&cs); }
~CriticalSection() { DeleteCriticalSection(&cs); }
void lock() { EnterCriticalSection(&cs); }
void unlock() { LeaveCriticalSection(&cs); }
};
class SRWLock
{
SRWLOCK srw;
public:
SRWLock() { InitializeSRWLock(&srw); }
void lock() { AcquireSRWLockExclusive(&srw); }
void unlock() { ReleaseSRWLockExclusive(&srw); }
};
}
template <class M>
void doLock(void *param)
{
M &m = *static_cast<M*>(param);
for (size_t n = 0; n < N; ++n)
{
m.lock();
var += std::rand();
m.unlock();
}
}
template <class M>
void runTest(size_t threadCount)
{
M m;
std::vector<std::thread> thrs(threadCount);
const auto start = std::chrono::system_clock::now();
for (auto &t : thrs) t = std::thread(doLock<M>, &m);
for (auto &t : thrs) t.join();
const auto end = std::chrono::system_clock::now();
const std::chrono::duration<double> diff = end - start;
std::cout << diff.count() << sep;
}
template <class ...Args>
void runTests(size_t threadMax)
{
{
int dummy[] = { (std::cout << typeid(Args).name() << sep, 0)... };
(void)dummy;
}
std::cout << std::endl;
for (size_t n = 1; n <= threadMax; ++n)
{
{
int dummy[] = { (runTest<Args>(n), 0)... };
(void)dummy;
}
std::cout << std::endl;
}
}
int main()
{
std::srand(time(NULL));
runTests<std::mutex, WinApi::CriticalSection, WinApi::SRWLock>(T);
return 0;
}
该测试项目是在 Microsoft Visual Studio 17 (15.8.2) 上构建为 Windows 控制台应用程序,具有以下设置:
- MFC的使用:在静态库中使用MFC
- Windows SDK版本:10.0.17134.0
- 平台工具集:Visual Studio 2017 (v141)
- 优化:O2、Oi、Oy-、GL
See Windows 关键部分 - 如何完全禁用旋转 https://stackoverflow.com/questions/54765280/windows-critical-section-how-to-disable-spinning-completely从Windows 8开始,微软改变了关键部分默认行为的实现(甚至在文档中没有任何文字)(如果您使用InitializeCriticalSection(&cs),您将在启用未记录的动态旋转调整算法的情况下旋转)。在这里查看我的评论:https://randomascii.wordpress.com/2012/06/05/in-praise-of-idleness/#comment-57420 https://randomascii.wordpress.com/2012/06/05/in-praise-of-idleness/#comment-57420
对于您的测试,请尝试使用 InitializeCriticalSectionAndSpinCount(&cs,1) 而不是 InitializeCriticalSection(&cs)。这应该使它的行为有点类似于 Windows 7,尽管在该领域还有很多其他变化。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)