By: GiGNiC (e.delete@this.ma.il), December 6, 2014 6:27 am
Room: Moderated Discussions
Eric Bron (eric.bron.delete@this.zvisuel.privatefortest.com) on December 6, 2014 4:04 am wrote:
> thank you for the information, I'll do some tests
>
> from the link
>
> http://en.cppreference.com/w/cpp/thread/mutex
>
> "A calling thread must not own the mutex prior to calling lock or try_lock."
>
> this doesn't fit with the behavior of Windows critical sections where you can
> enter several times the same CS from the thread which own it already (and don't
> have to leave it the same number of times unlike with std::recursive_mutex)
>
> so I'm not sure of the behavior with the MS VC++ implementation if it's based
> on Windows critical sections, maybe the behavior is implementation dépendent
> which looks odd for something were validation is so much important
>
There's also std::recursive_mutex which can be locked multiple times by the same thread, but it's about the same for performance.
I'm fairly convinced VC12 (VS2013) doesn't base either on the standard Windows CRITICAL_SECTION.
(code stolen from stackoverflow:)
with the following results:
> thank you for the information, I'll do some tests
>
> from the link
>
> http://en.cppreference.com/w/cpp/thread/mutex
>
> "A calling thread must not own the mutex prior to calling lock or try_lock."
>
> this doesn't fit with the behavior of Windows critical sections where you can
> enter several times the same CS from the thread which own it already (and don't
> have to leave it the same number of times unlike with std::recursive_mutex)
>
> so I'm not sure of the behavior with the MS VC++ implementation if it's based
> on Windows critical sections, maybe the behavior is implementation dépendent
> which looks odd for something were validation is so much important
>
There's also std::recursive_mutex which can be locked multiple times by the same thread, but it's about the same for performance.
I'm fairly convinced VC12 (VS2013) doesn't base either on the standard Windows CRITICAL_SECTION.
(code stolen from stackoverflow:)
#include
#include
#include
#include
#include
#include
const int g_cRepeatCount = 1000000;
const int g_cThreadCount = 16;
double g_shmem = 8;
std::mutex g_mutex;
std::recursive_mutex g_recmtx;
CRITICAL_SECTION g_critSec;
void sharedFunc(int i)
{
if(i % 2 == 0) g_shmem = sqrt(g_shmem);
else g_shmem *= g_shmem;
}
void threadFuncMutex()
{
for(int i = 0; i < g_cRepeatCount; ++i) {
g_mutex.lock();
sharedFunc(i);
g_mutex.unlock();
}
}
void threadFuncRecMtx()
{
for(int i = 0; i < g_cRepeatCount; ++i) {
g_recmtx.lock();
sharedFunc(i);
g_recmtx.unlock();
}
}
void threadFuncCritSec()
{
for(int i = 0; i < g_cRepeatCount; ++i) {
EnterCriticalSection(&g_critSec);
sharedFunc(i);
LeaveCriticalSection(&g_critSec);
}
}
void testRound(int threadCount)
{
std::vector 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(endMutex - startMutex).count();
std::cout << "usnr";
threads.clear();
auto startRecMtx = std::chrono::high_resolution_clock::now();
for(int i = 0; i < threadCount; ++i) threads.push_back(std::thread(threadFuncRecMtx));
for(std::thread & thd : threads) thd.join();
auto endRecMtx = std::chrono::high_resolution_clock::now();
std::cout << "std::recursive_mutex: ";
std::cout << std::chrono::duration_cast(endRecMtx - startRecMtx).count();
std::cout << "usnr";
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(endCritSec - startCritSec).count();
std::cout << "usnr";
}
int main(int argc, TCHAR* argv[])
{
InitializeCriticalSection(&g_critSec);
std::cout << "Iterations: " << g_cRepeatCount << "nr";
for(int i = 1; i <= g_cThreadCount; i *= 2) {
std::cout << "Thread count: " << i << "nr";
testRound(i);
Sleep(1000);
}
getchar();
DeleteCriticalSection(&g_critSec);
return 0;
}
with the following results:
Iterations: 1000000
Thread count: 1
std::mutex: 52002us
std::recursive_mutex: 51002us
CRITICAL_SECTION: 23001us
Thread count: 2
std::mutex: 448025us
std::recursive_mutex: 442025us
CRITICAL_SECTION: 106006us
Thread count: 4
std::mutex: 884050us
std::recursive_mutex: 893051us
CRITICAL_SECTION: 197011us
Thread count: 8
std::mutex: 70695043us
std::recursive_mutex: 73504204us
CRITICAL_SECTION: 273015us
Thread count: 16
std::mutex: 147516437us
std::recursive_mutex: 156276938us
CRITICAL_SECTION: 440025us