3

我写了一个小程序来比较 Windows 中 Critical Section 与 Mutex 的性能。

在我运行的测试中,获取关键部分似乎更慢:O 谁能解释为什么这两件事花费几乎相同的时间,以及内部发生了什么。

这是我使用的计时器 - http://cplus.about.com/od/howtodothingsi2/a/timing.htm

#include "stdafx.h"
#include<iostream>
#include<vector>
#include "h_timer.h"
#include<WinBase.h>
#include<Windows.h>
#include<stdio.h>

#define MAX_THREADS 2000  
//Comment and Uncomment this to enable/disable critialSection / Mutex
#define CRIT 1

using namespace std;

HANDLE Mutex;
CRITICAL_SECTION critSection;
DWORD WINAPI Contention( LPVOID );

int main( void )
{
    HANDLE Thread[MAX_THREADS];
    DWORD ThreadID;
    int i;

#ifdef CRIT
//create a critical section
InitializeCriticalSection(&critSection);
#else

    // Create a mutex with no initial owner
    Mutex = CreateMutex( NULL, FALSE,NULL);

#endif

    // Create worker threads

CStopWatch timer, tempTimer;
timer.startTimer();
    for( i=0; i < MAX_THREADS; i++ )
    {
        Thread[i] = CreateThread( NULL,
                     0,(LPTHREAD_START_ROUTINE)Contention,NULL,0,&ThreadID);
    }
    WaitForMultipleObjects(MAX_THREADS, Thread, TRUE, INFINITE);

    timer.stopTimer();
    cout<<endl<<"Elapsed Time:"<<timer.getElapsedTime();
    cin.get();
    // Close thread and mutex handles

    for( i=0; i < MAX_THREADS; i++ )
    CloseHandle(Thread[i]);

    CloseHandle(Mutex);
    return 0;
}


DWORD WINAPI Contention( LPVOID lpParam )
{
    #ifdef CRIT
EnterCriticalSection(&critSection);
//printf("ThreadId: %d\n",GetCurrentThreadId());
//printf("Let's try Again. %d\n\n", GetCurrentThreadId());
LeaveCriticalSection(&critSection);

#else
// lpParam not used in this example
    UNREFERENCED_PARAMETER(lpParam);
    DWORD dwCount=0, dwWaitResult;

    // Request ownership of mutex.
    dwWaitResult = WaitForSingleObject(
            ghMutex, // handle to mutex
            INFINITE); // no time-out interval
        dwCount++;
    ReleaseMutex(ghMutex);
#endif

return TRUE;
}

对于 2000 个线程,在四核 HPZ210 上,两者都需要大约 1.5 秒。

4

2 回答 2

13

我认为有两个因素:

主要是 - 您的程序主要是线程创建开销。您正在创建和销毁 2000 个线程,并且每个线程仅访问一次互斥锁/CS。创建线程所花费的时间淹没了锁定/解锁时间的差异。

另外 - 您可能没有测试这些锁优化的用例。尝试生成两个线程,每个线程都尝试访问互斥锁/CS 数千次。

于 2012-07-04T01:49:16.293 回答
9

关键部分是用户模式和内核模式的混合体。他们试图通过使用自旋锁(用户模式)来阻止您的线程进行上下文切换,然后再使用更昂贵的信号量(内核模式)。这提高了实际场景中的性能。相反,互斥锁是纯粹的内核模式,会立即等待,执行上下文切换。

通过在 2000 个线程之间进行 100% 的争用,您已经做到了,因此临界区几乎肯定会尽可能多地旋转,占用 CPU,然后最终完全执行互斥锁所做的事情并在内核模式下执行等待。因此,他们在这种情况下放慢速度是有道理的。

和japreiss所说的。线程创建非常慢。

于 2012-07-04T01:57:30.707 回答