Veuillez consulter mes mises à jour à la fin de la réponse, la situation a radicalement changé depuis Visual Studio 2015. La réponse originale est ci-dessous.
J'ai fait un test très simple et d'après mes mesures, la std::mutex
est environ 50-70x plus lent que CRITICAL_SECTION
.
std::mutex: 18140574us
CRITICAL_SECTION: 296874us
Edit : Après quelques tests supplémentaires, il s'est avéré que cela dépend du nombre de threads (congestion) et du nombre de cœurs du CPU. En général, le std::mutex
est plus lent, mais de combien, cela dépend de l'utilisation. Voici les résultats des tests mis à jour (testés sur MacBook Pro avec Core i5-4258U, Windows 10, Bootcamp) :
Iterations: 1000000
Thread count: 1
std::mutex: 78132us
CRITICAL_SECTION: 31252us
Thread count: 2
std::mutex: 687538us
CRITICAL_SECTION: 140648us
Thread count: 4
std::mutex: 1031277us
CRITICAL_SECTION: 703180us
Thread count: 8
std::mutex: 86779418us
CRITICAL_SECTION: 1634123us
Thread count: 16
std::mutex: 172916124us
CRITICAL_SECTION: 3390895us
Voici le code qui a produit ce résultat. Compilé avec Visual Studio 2012, paramètres de projet par défaut, configuration de la version Win32. Veuillez noter que ce test n'est peut-être pas parfaitement correct, mais il m'a fait réfléchir à deux fois avant de changer mon code pour passer de l'utilisation de CRITICAL_SECTION
à std::mutex
.
#include "stdafx.h"
#include <Windows.h>
#include <mutex>
#include <thread>
#include <vector>
#include <chrono>
#include <iostream>
const int g_cRepeatCount = 1000000;
const int g_cThreadCount = 16;
double g_shmem = 8;
std::mutex g_mutex;
CRITICAL_SECTION g_critSec;
void sharedFunc( int i )
{
if ( i % 2 == 0 )
g_shmem = sqrt(g_shmem);
else
g_shmem *= g_shmem;
}
void threadFuncCritSec() {
for ( int i = 0; i < g_cRepeatCount; ++i ) {
EnterCriticalSection( &g_critSec );
sharedFunc(i);
LeaveCriticalSection( &g_critSec );
}
}
void threadFuncMutex() {
for ( int i = 0; i < g_cRepeatCount; ++i ) {
g_mutex.lock();
sharedFunc(i);
g_mutex.unlock();
}
}
void testRound(int threadCount)
{
std::vector<std::thread> threads;
auto startMutex = std::chrono::high_resolution_clock::now();
for (int i = 0; i<threadCount; ++i)
threads.push_back(std::thread( threadFuncMutex ));
for ( std::thread& thd : threads )
thd.join();
auto endMutex = std::chrono::high_resolution_clock::now();
std::cout << "std::mutex: ";
std::cout << std::chrono::duration_cast<std::chrono::microseconds>(endMutex - startMutex).count();
std::cout << "us \n\r";
threads.clear();
auto startCritSec = std::chrono::high_resolution_clock::now();
for (int i = 0; i<threadCount; ++i)
threads.push_back(std::thread( threadFuncCritSec ));
for ( std::thread& thd : threads )
thd.join();
auto endCritSec = std::chrono::high_resolution_clock::now();
std::cout << "CRITICAL_SECTION: ";
std::cout << std::chrono::duration_cast<std::chrono::microseconds>(endCritSec - startCritSec).count();
std::cout << "us \n\r";
}
int _tmain(int argc, _TCHAR* argv[]) {
InitializeCriticalSection( &g_critSec );
std::cout << "Iterations: " << g_cRepeatCount << "\n\r";
for (int i = 1; i <= g_cThreadCount; i = i*2) {
std::cout << "Thread count: " << i << "\n\r";
testRound(i);
Sleep(1000);
}
DeleteCriticalSection( &g_critSec );
// Added 10/27/2017 to try to prevent the compiler to completely
// optimize out the code around g_shmem if it wouldn't be used anywhere.
std::cout << "Shared variable value: " << g_shmem << std::endl;
getchar();
return 0;
}
Mise à jour du 27/10/2017 (1) : Certaines réponses suggèrent que ce test n'est pas réaliste ou ne représente pas un scénario du "monde réel". C'est vrai, ce test tente de mesurer la Transparent de la std::mutex
il ne s'agit pas de prouver que la différence est négligeable pour 99 % des applications.
Mise à jour du 27/10/2017 (2) : Il semble que la situation ait changé en faveur de std::mutex
depuis Visual Studio 2015 (VC140). J'ai utilisé l'IDE VS2017, exactement le même code que ci-dessus, configuration de la version x64, optimisations désactivées et j'ai simplement changé le "Platform Toolset" pour chaque test. Les résultats sont très surprenants et je suis vraiment curieux de savoir ce qui a changé dans VC140.
Mise à jour 25/02/2020 (3) : Reran le test avec Visual Studio 2019 (Toolset v142), et la situation est toujours la même : std::mutex
est deux à trois fois plus rapide que CRITICAL_SECTION
.