Похоже, что производительность CRITICAL_SECTION стала хуже в Windows 8 и выше. (см. графики ниже)
Тест довольно прост: некоторые параллельные потоки делают по 3 миллиона блокировок каждый для доступа исключительно к переменной. Вы можете найти программу на C ++ внизу вопроса. Я запускаю тест на Windows Vista, Windows 7, Windows 8, Windows 10 (x64, VMWare, Intel Core i7-2600 3,40 ГГц).
Результаты на картинке ниже.
Ось X — количество одновременных потоков.
Ось Y — это прошедшее время в секундах (чем ниже, тем лучше).
Что мы можем увидеть:
SRWLock
производительность примерно одинакова для всех платформCriticalSection
производительность стала хуже относительно SRWL на Windows 8 и выше Вопрос в том: Кто-нибудь может объяснить, почему производительность CRITICAL_SECTION стала хуже на Win8 и выше?
Некоторые заметки:
std::mutex
реализация для Windows Vista основана на CRITICAL_SECTION
, но для Win7 и выше std::mutex
основан на SWRL. Это верно как для MSVS17, так и для 15 (чтобы убедиться, что primitives.h
файл при установке MSVC ++ и ищите stl_critical_section_vista
а также stl_critical_section_win7
классы) Это объясняет разницу между производительностью std :: mutex в Win Vista и другими.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;
}
Тестовый проект был построен как консольное приложение Windows в Microsoft Visual Studio 17 (15.8.2) со следующими настройками:
Задача ещё не решена.
Других решений пока нет …