在Win32平台上进行多线程编程,常会用到锁。下边用C++实现了互斥对象(Mutex)锁和临界区(CRITICAL_SECTION)锁,以加深理解和今后方便使用。代码已在VS2005环境下编译测试通过。
Lock.h
- #ifndef _Lock_H
- #define _Lock_H
-
- #include <windows.h>
-
-
-
- class ILock
- {
- public:
- virtual ~ILock() {}
-
- virtual void Lock() const = 0;
- virtual void Unlock() const = 0;
- };
-
-
- class Mutex : public ILock
- {
- public:
- Mutex();
- ~Mutex();
-
- virtual void Lock() const;
- virtual void Unlock() const;
-
- private:
- HANDLE m_mutex;
- };
-
-
- class CriSection : public ILock
- {
- public:
- CriSection();
- ~CriSection();
-
- virtual void Lock() const;
- virtual void Unlock() const;
-
- private:
- CRITICAL_SECTION m_critclSection;
- };
-
-
-
- class CMyLock
- {
- public:
- CMyLock(const ILock&);
- ~CMyLock();
-
- private:
- const ILock& m_lock;
- };
-
-
- #endif
Lock.cpp
- #include "Lock.h"
-
-
-
-
- Mutex::Mutex()
- {
- m_mutex = ::CreateMutex(NULL, FALSE, NULL);
- }
-
-
- Mutex::~Mutex()
- {
- ::CloseHandle(m_mutex);
- }
-
-
- void Mutex::Lock() const
- {
- DWORD d = WaitForSingleObject(m_mutex, INFINITE);
- }
-
-
- void Mutex::Unlock() const
- {
- ::ReleaseMutex(m_mutex);
- }
-
-
-
-
- CriSection::CriSection()
- {
- ::InitializeCriticalSection(&m_critclSection);
- }
-
-
- CriSection::~CriSection()
- {
- ::DeleteCriticalSection(&m_critclSection);
- }
-
-
- void CriSection::Lock() const
- {
- ::EnterCriticalSection((LPCRITICAL_SECTION)&m_critclSection);
- }
-
-
- void CriSection::Unlock() const
- {
- ::LeaveCriticalSection((LPCRITICAL_SECTION)&m_critclSection);
- }
-
-
-
-
- CMyLock::CMyLock(const ILock& m) : m_lock(m)
- {
- m_lock.Lock();
- }
-
-
- CMyLock::~CMyLock()
- {
- m_lock.Unlock();
- }
下边是测试代码
-
-
-
- #include <iostream>
- #include <process.h>
- #include <time.h>
- #include "Lock.h"
-
- using namespace std;
-
-
- #define ENABLE_MUTEX
- #define ENABLE_CRITICAL_SECTION
-
-
- #if defined (ENABLE_MUTEX)
-
-
- Mutex g_Lock;
-
- #elif defined (ENABLE_CRITICAL_SECTION)
-
-
- CriSection g_Lock;
-
- #endif
-
-
- void LockCompare(int &iNum)
- {
- CMyLock lock1(g_Lock);
-
- iNum++;
- }
-
-
-
- unsigned int __stdcall StartThread(void *pParam)
- {
- char *pMsg = (char *)pParam;
- if (!pMsg)
- {
- return (unsigned int)1;
- }
-
- CMyLock lock2(g_Lock);
-
- clock_t tStart,tEnd;
-
- tStart = clock();
-
- int iNum = 0;
- for (int i = 0; i < 100000; i++)
- {
- LockCompare(iNum);
- }
-
- tEnd = clock();
- #if defined (ENABLE_MUTEX)
-
- cout<<"The lock type is mutex, time = "<<(tEnd - tStart)<<" ms."<<endl;
-
- #elif defined (ENABLE_CRITICAL_SECTION)
-
- cout<<"The lock type is critical section, time = "<<(tEnd - tStart)<<" ms."<<endl;
-
- #endif
-
- return (unsigned int)0;
- }
-
- int main(int argc, char* argv[])
- {
- HANDLE hThread1, hThread2;
- unsigned int uiThreadId1, uiThreadId2;
-
- char *pMsg1 = "First print thread.";
- char *pMsg2 = "Second print thread.";
-
-
- hThread1 = (HANDLE)_beginthreadex(NULL, 0, &StartThread, (void *)pMsg1, 0, &uiThreadId1);
- hThread2 = (HANDLE)_beginthreadex(NULL, 0, &StartThread, (void *)pMsg2, 0, &uiThreadId2);
-
-
- DWORD dwRet = WaitForSingleObject(hThread1,INFINITE);
- if ( dwRet == WAIT_TIMEOUT )
- {
- TerminateThread(hThread1,0);
- }
- dwRet = WaitForSingleObject(hThread2,INFINITE);
- if ( dwRet == WAIT_TIMEOUT )
- {
- TerminateThread(hThread2,0);
- }
-
-
- ::CloseHandle(hThread1);
- ::CloseHandle(hThread2);
-
- system("pause");
- return 0;
- }
在线程函数StartThread中,循环100000次,对保护资源“iNum ”反复加锁,解锁。编译,运行5次,将每次打印的线程锁切换耗时时间记录下来。之后,将测试代码中的宏 #define ENABLE_MUTEX 注释掉,禁掉互斥锁,启用临界区锁,重新编译代码,运行5次。下边是分别是互斥锁和临界区锁耗时记录(不同机器上耗时会不同):
互斥锁
线程Id |
耗时 / ms |
总计 |
1 |
141 |
125 |
125 |
125 |
125 |
641 |
2 |
140 |
125 |
140 |
125 |
156 |
686 |
临界区锁
线程Id |
耗时 / ms |
总计 |
1 |
15 |
16 |
31 |
31 |
31 |
124 |
2 |
31 |
31 |
31 |
16 |
31 |
140 |
互斥锁总共耗时:641+686=1327 ms,而临界区锁:124+140=264 ms。显而易见,临界区锁耗时比互斥锁耗时节约了大概5倍的时间。
总结:1、在同一个进程的多线程同步锁,宜用临界区锁,它比较节约线程上下文切换带来的系统开销。但因临界区工作在用户模式下,所以不能对不同进程中的多线程进行同步。2、因互斥对象锁属于内核对象,所以在进行多线程同步时速度会比较慢,但是可以在不同进程的多个线程之间进行同步。
转自:http://blog.csdn.net/chexlong/article/details/7060425