现在的位置: 首页 > 综合 > 正文

Win32线程锁的一种高效实现

2014年03月22日 ⁄ 综合 ⁄ 共 4070字 ⁄ 字号 评论关闭
             Win32线程锁的一种高效实现

             Horin|贺勤
        Email: horin153@msn.com
        Blog: http://blog.csdn.net/horin153/

    最近看 MSDN 中的一些资料,有感于世界变化真快,从前掌握的锁的知识实在肤浅;于是毫不犹豫地将其拖入回收站,顺便也有了这篇文章。

    在这里我不粘贴 MSDN 中的大段叙述,也不复述锁的知识。仅谈新锁的特点:

1、根据 os 版本来决定线程切换方式: Win9x 用 Sleep, WinNT 用 SwitchToThread。
    调用 Sleep(0) 时,调用线程虽会放弃剩余时间片,但仍保持 ready 状态。而 SwitchToThread 会促使 os 重新调度线程,并可能使低优先级的线程运行;该接口在 Win9x 系统中不可用。

2、根据 cpu 个数来决定是否 spin: 单 cpu 直接切换线程, 多 cpu 则 spin。
    和 InitializeCriticalSectionAndSpinCount 相似,单处理器系统直接切换线程,不进行 spin 处理。

    实现代码如下:
// --------------------- code begin -----------------------

class CSpinInterlocked
{
public:
    CSpinInterlocked(DWORD processor_num=1, bool win9x=false, int spin_count=128)
    : _atomic_mutex(0)
    , _spin_count(spin_count)
    {
        _switch_thread = win9x ? &CSpinInterlocked::switch_thread_9x : /
            &CSpinInterlocked::switch_thread_nt;
        _lock = (processor_num == 1) ? &CSpinInterlocked::lock_single_processor : /
            &CSpinInterlocked::lock_multi_processor;
    }

    ~CSpinInterlocked() {
    }

    void lock(void) {
        (this->*_lock)();
    }

    void unlock(void)   {
        ::InterlockedExchange(&_atomic_mutex, 0);
    }

private:
    typedef void (CSpinInterlocked::*pFun)(void);
    long volatile _atomic_mutex;
    int _spin_count;

    pFun _switch_thread;
    pFun _lock;

    void lock_single_processor(void)    {
        if (::InterlockedExchange(&_atomic_mutex, 1))   {
            // On single-processor systems, yield execution.
            (this->*_switch_thread)();
        }
    }

    void lock_multi_processor(void)
    {
        if (::InterlockedExchange(&_atomic_mutex, 1))   {
            // On multi-processor systems, start a spin.
            for (int i = 0; ::InterlockedExchange(&_atomic_mutex, 1) && /
                i<_spin_count; ++i) {
                (this->*_switch_thread)();
            }

            if (i >= _spin_count) {
                while(::InterlockedExchange(&_atomic_mutex, 1)) {
                    ::Sleep(50);
                }
            }
        }
    }

    void switch_thread_9x(void) {
        ::Sleep(0); // on Win98
    }

    //#define _WIN32_WINNT 0x0400
    void switch_thread_nt(void) {
        ::SwitchToThread(); // on WinNT
    }
};

// ---------------------- code end ------------------------

    对 CSpinInterlocked 进行了简单测试,在 WinXP sp2 + Intel P4 HT 2.8G 上, 直觉上  CriticalSection 比 CSpinInterlocked 效率高。这也许是超线程的影响。
    相比 CriticalSection 只能用于进程内的线程间的局限,如果把 CSpinInterlocked 实现在共享内存中,则可以用于进程间。

附测试代码:

// --------------------- code begin -----------------------

CSpinInterlocked g_lock = CSpinInterlocked(get_processor_num(), is_win9x());
// get_processor_num(): 获取处理器数;
// is_win9x(): 判断 os 是否是 Win9x?
int g_count = 0;
int _add_types = 10000;

DWORD WINAPI ThreadFunc( LPVOID lpParam )
{
    g_lock.lock();
    DWORD _id = reinterpret_cast<DWORD>(lpParam);
    cout << "Thread start:" << _id << endl;
    for (int i=_add_types; i>0; --i) {
        ++g_count;
    }
    cout << "Thread quit:" << _id << endl;
    g_lock.unlock();
    return EXIT_SUCCESS;
}

int main(void)
{
    DWORD dwThreadId = 0, thread_num = 20;
    HANDLE hThread = NULL;

    for (DWORD i=0; i<thread_num; i++){
        hThread = ::CreateThread(
            NULL,           // default security attributes
            0,              // use default stack size
            ThreadFunc,     // thread function
            reinterpret_cast<LPVOID>(i),    // argument to thread function
            0,              // use default creation flags
            &dwThreadId);   // returns the thread identifier

        if (hThread == NULL) {
            cerr << "CreateThread failed:" << i << endl;
        }
    }

    ::Sleep(2000);
    // 不加锁时, g_count 一般应该小于 20 * 10000.
    // 成功加锁后, g_count 应该等于 20 * 10000.
    cout << "g_count=" << g_count << endl;
    if (g_count != 20 * 10000)  {
        cerr << "Thread lock ERROR!" << endl;
    }
}

// ---------------------- code end ------------------------

    测试用例的一种输出结果如下:

Thread start:0
Thread quit:0
Thread start:8
Thread quit:8
Thread start:4
Thread quit:4
Thread start:5
Thread quit:5
Thread start:16
Thread quit:16
Thread start:2
Thread quit:2
Thread start:1
Thread quit:1
Thread start:19
Thread quit:19
Thread start:13
Thread quit:13
Thread start:14
Thread quit:14
Thread start:15
Thread quit:15
Thread start:12
Thread quit:12
Thread start:7
Thread quit:7
Thread start:6
Thread quit:6
Thread start:11
Thread quit:11
Thread start:18
Thread quit:18
Thread start:3
Thread quit:3
Thread start:10
Thread quit:10
Thread start:9
Thread quit:9
Thread start:17
Thread quit:17
g_count=200000

抱歉!评论已关闭.