2013-12-13 41 views
1

WinAPI下有WaitForSingleObject()和ReleaseMutex()函数对。还有Interlocked *()函数系列。我决定在捕获单个互斥锁和交换互锁变量之间检查性能。WaitForSingleObject vs Interlocked *

HANDLE mutex; 
WaitForSingleObject(mutex, INFINITE); 
// .. 
ReleaseMutex(mutex); 

// 0 unlocked, 1 locked 
LONG lock = 0; 
while(InterlockedCompareExchange(&lock, 1, 0)) 
    SwitchToThread(); 
// .. 
InterlockedExchange(&lock, 0); 
SwitchToThread(); 

我测量了这两种方法之间的性能,发现使用Interlocked *()的速度快了大约38%。为什么这样?

这里是我的性能测试:

#include <windows.h> 
#include <iostream> 
#include <conio.h> 
using namespace std; 

LONG interlocked_variable = 0; // 0 unlocked, 1 locked 
int run      = 1; 

DWORD WINAPI thread(LPVOID lpParam) 
{ 
    while(run) 
    { 
     while(InterlockedCompareExchange(&interlocked_variable, 1, 0)) 
      SwitchToThread(); 
     ++(*((unsigned int*)lpParam)); 
     InterlockedExchange(&interlocked_variable, 0); 
     SwitchToThread(); 
    } 

    return 0; 
} 

int main() 
{ 
    unsigned int num_threads; 
    cout << "number of threads: "; 
    cin >> num_threads; 
    unsigned int* num_cycles = new unsigned int[num_threads]; 
    DWORD s_time, e_time; 

    s_time = GetTickCount(); 
    for(unsigned int i = 0; i < num_threads; ++i) 
    { 
     num_cycles[i] = 0; 
     HANDLE handle = CreateThread(NULL, NULL, thread, &num_cycles[i], NULL, NULL); 
     CloseHandle(handle); 
    } 
    _getch(); 
    run = 0; 
    e_time = GetTickCount(); 

    unsigned long long total = 0; 
    for(unsigned int i = 0; i < num_threads; ++i) 
     total += num_cycles[i]; 
    for(unsigned int i = 0; i < num_threads; ++i) 
     cout << "\nthread " << i << ":\t" << num_cycles[i] << " cyc\t" << ((double)num_cycles[i]/(double)total) * 100 << "%"; 
    cout << "\n----------------\n" 
     << "cycles total:\t" << total 
     << "\ntime elapsed:\t" << e_time - s_time << " ms" 
     << "\n----------------" 
     << '\n' << (double)(e_time - s_time)/(double)(total) << " ms\\op\n"; 

    delete[] num_cycles; 
    _getch(); 
    return 0; 
} 
+1

互斥锁是跨进程同步的内核对象,因此每个锁定/解锁都涉及上下文切换。 [见此处](http://msdn.microsoft.com/en-us/magazine/cc163726.aspx)进行相关讨论。 –

+1

据我所知,互斥锁更适合多个进程之间的同步。您可能还想尝试一个关键部分。 – Paul

+0

你是如何测试性能的?在锁上有没有实际的争用? –

回答

3

WaitForSingleObject并不一定会更快。它涵盖了更广泛的同步场景范围,尤其是您可以等待不属于您的进程并因此进程间同步的句柄。考虑到所有这一切,只有根据您的测试慢了38%。

如果您的流程中包含了所有内容,并且每纳秒计数一次,InterlockedXxx可能是更好的选择,但它绝对不是绝对优越的选择。

此外,你可能想看看Slim Reader/Writer (SRW) Locks API。您或许可以纯粹基于InterlockedXxx构建类似的类/功能,并且性能略好,但重要的是,通过SRW,您可以立即使用它,并具备记录的行为,稳定且性能良好。

3

您没有比较等效的锁,因此性能如此不同并不奇怪。

互斥锁允许跨进程锁定,由于其提供的灵活性,它可能是最昂贵的锁定方法之一。当你阻塞一个锁时,它通常会让你的线程进入睡眠状态,直到你被唤醒后才会使用cpu。这允许其他代码使用cpu。

您的InterlockedCompareExchange()代码是一个简单的自旋锁。你会刻录CPU等待你的锁。

您可能还需要寻找到Critical Sections(不是互斥的开销更少)和Slim Reader/Writer Locks(可用于互斥如果你总是获取排它锁并提供分数更快的性能比无争议的使用关键部分,根据我的测试)。

您可能还想读肯尼克尔的"The Evolution of Synchronization in Windows and C++"和Preshing的锁相关的东西,herehere

相关问题