多线程基础之五:Windows API提供的mutex和semaphore性能比较

Windows系统提供HANDLE WINAPI CreateSemaphore(xxx)HANDLE WINAPI CreateMutex(xxx)直接提供Mutex和Semaphore两种内核对象供程序员使用在临界区互斥操作。在前面的多线程基础之一提到过Semaphore存在Binary和Counting两种,其中Binary Semaphore等同于Mutex,而Counting Semaphores则存在资源计数的选项,并且还存在可以为Counting Semaphores配备等待队列实现非阻塞请求以实现加速操作。

但是我们仔细查看创建Semaphore的Windows API:

HANDLE WINAPI CreateSemaphore( 
  _In_opt_  LPSECURITY_ATTRIBUTES lpSemaphoreAttributes 
  _In_      LONG lInitialCount, 
  _In_      LONG lMaximumCount, 
  _In_opt_  LPCTSTR lpName 
);
第一个参数:安全属性,如果为NULL则是默认安全属性 
第二个参数:信号量的初始值,要>=0<=第三个参数 
第三个参数:信号量的最大值,即最大资源数目 
第四个参数:信号量的名称,一般不涉及到跨进程使用基本都是输入NULL的。 

可以发现并不存在开关配备等待队列的选项,是否这意味着Windows系统提供的Semaphore并没有提供这一选项还是内嵌了等待队列?这需要代码检验一下。

test_time_Mutex.cpp

#include <iostream>
#include <Windows.h>
#include <time.h>
using namespace std;

HANDLE  g_hMutex = NULL;
const int g_Number = 50;
const int killTimeStep = 100000000;
DWORD WINAPI ThreadProc(__in  LPVOID lpParameter);

int main()
{
    clock_t start_time = clock();

    //TRUE代表主线程拥有互斥对象 但是主线程没有释放该对象  互斥对象谁拥有 谁释放 
    g_hMutex = CreateMutex(NULL,TRUE,NULL);
    printf("主线程创建时便占有了互斥对象,没有释放,所以其他子线程无法使用。\n");

    HANDLE hThread[ g_Number ] = {0}; //创建50个线程

    int first = 1;
    for (int i=0; i<g_Number; i++)
    hThread[i] = CreateThread(NULL, 0, ThreadProc, (LPVOID)first++, 0, NULL);

    printf("创建大规模子线程成功\n");

    ReleaseMutex(g_hMutex);
    printf("主线程释放了互斥对象,其他子线程可以开始使用。\n");

    WaitForMultipleObjects(g_Number,hThread,TRUE,INFINITE);

    for (int i=0; i<g_Number; i++)
    CloseHandle( hThread[i] );

    CloseHandle( g_hMutex );
    clock_t end_time = clock();
    cout<<"Running time is:"<<static_cast<double>(end_time - start_time)/CLOCKS_PER_SEC*1000<<"ms"<<endl;
    return 0;
}

DWORD WINAPI ThreadProc(__in  LPVOID lpParameter)
{
    WaitForSingleObject(g_hMutex, INFINITE);//等待互斥量
    cout<<(int)lpParameter<<endl;
    int i = killTimeStep;
    while(i--);
    ReleaseMutex(g_hMutex);//释放互斥量
    return 0;
}

运行结果
这里写图片描述
********************************……********************************
这里写图片描述
test_time_Semaphores.cpp

#include <iostream>
#include <Windows.h>
#include <time.h>
using namespace std;

HANDLE  g_Sema = NULL;
const int g_Number = 50;
const int killTimeStep = 100000000;
DWORD WINAPI ThreadProc(__in  LPVOID lpParameter);

int main()
{
    clock_t start_time = clock();

    g_Sema = CreateSemaphore(NULL,0,3,NULL); 
    printf("主线程创建时便占有了互斥对象,没有释放,所以其他子线程无法使用。\n");
    ReleaseSemaphore(g_Sema,1,NULL);
    printf("主线程释放了互斥对象,其他子线程可以开始使用。\n");

    HANDLE hThread[ g_Number ] = {0}; //创建50个线程

    int first = 1;
    for (int i=0; i<g_Number; i++)
    hThread[i] = CreateThread(NULL, 0, ThreadProc, (LPVOID)first++, 0, NULL);

    WaitForMultipleObjects(g_Number,hThread,TRUE,INFINITE);

    for (int i=0; i<g_Number; i++)
    CloseHandle( hThread[i] );

    CloseHandle( g_Sema );
    clock_t end_time = clock();
    cout<<"Running time is:"<<static_cast<double>(end_time - start_time)/CLOCKS_PER_SEC*1000<<"ms"<<endl;
    return 0;
}

DWORD WINAPI ThreadProc(__in  LPVOID lpParameter)
{
    WaitForSingleObject(g_Sema, INFINITE);//等待信号量 
    cout<<(int)lpParameter<<endl; 
    int i = killTimeStep;
    while(i--);
    ReleaseSemaphore(g_Sema,1,NULL);//释放信号量 
    return 0; 
}

运行结果
这里写图片描述
********************************……********************************
这里写图片描述

Conclusion: 可以看到Windows确实没有为Semaphore配备等待队列,所以导致在测试代码中Semaphore和Mutex在同样的条件下都是采用“阻塞”请求机制,即在线程获取CPU的轮转时间片时,会一直调用WaitForSingleObject(xxx)询问情况,直到耗光本轮时间片或得到互斥对象。

对于操作损耗较短的临界区,性能影响并不明显(进程上下文切换的花费甚至可能还抵不过进程非阻塞请求节省下来的时间)。但是如果临界区的操作消耗时间较长,显然为Semaphore配备等待队列机制是存在需求的。参见多线程基础之六:采用Pthread Win32提供的配备等待队列的Semaphore填补Windows未提供非阻塞请求的Semaphore机制。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值