1 #include <windows.h> 2 3 CRITICAL_SECTION cs;//定义临界区对象 4 InitializeCriticalSection(&cs);//初始化临界区 5 EnterCriticalSection(&cs);//进入临界区 6 LeaveCriticalSection(&cs);//离开临界区 7 DeleteCriticalSection(&cs);//删除临界区
1 //=====================MyCriticalSection.h=========================== 2 #ifndef _My_CRITICAL_SECTION_H 3 #define _My_CRITICAL_SECTION_H 4 5 #include <windows.h> 6 //对临界区同样进行封装 7 class CMyCriticalSection 8 { 9 public: 10 CMyCriticalSection() 11 { 12 InitializeCriticalSection(&m_cSection); 13 } 14 15 void Lock() 16 { 17 EnterCriticalSection(&m_cSection); 18 } 19 20 void UnLock() 21 { 22 LeaveCriticalSection(&m_cSection); 23 } 24 25 26 //利用析构函数删除临界区对象 27 virtual ~CMyCriticalSection() 28 { 29 DeleteCriticalSection(&m_cSection); 30 } 31 private: 32 CRITICAL_SECTION m_cSection; 33 }; 34 35 class CCriticalSectionAutoLock 36 { 37 public: 38 //利用构造函数上锁,即进去临界区 39 CCriticalSectionAutoLock(CMyCriticalSection *mySection) 40 :pCMySection(mySection) 41 { 42 pCMySection->Lock(); 43 } 44 45 //利用析构函数解锁,即离开临界区 46 virtual ~CCriticalSectionAutoLock() 47 { 48 pCMySection->UnLock(); 49 } 50 private: 51 CMyCriticalSection *pCMySection; 52 }; 53 54 #endif
1 #include <iostream> 2 #include <windows.h> 3 #include "MySemaphore.h" 4 #include "MyMutex.h" 5 #include "MyCriticalSection.h" 6 using namespace std; 7 8 //HANDLE g_hSemaphore = NULL; 9 //HANDLE g_hMutex = NULL; 10 11 CMySemaphore MySemaphore; //信号量 12 CMyMutex MyMutex; //互斥量 13 CMyCriticalSection MyCriticalSection; //临界区 14 15 DWORD WINAPI Fun(LPVOID lpParamter) 16 { 17 string strPrint((const char*)lpParamter); 18 int iRunTime = 0; 19 //执行100次跳出 20 while(++iRunTime<10) 21 { 22 { 23 CCriticalSectionAutoLock cLock(&MyCriticalSection); 24 cout <<"["<< iRunTime <<"]:"<< strPrint.c_str()<<endl; 25 } 26 Sleep(1); //若去掉此句 可能导致其他线程无法进入临界区,因为 cLock在这之前析构,离开临界区 27 28 } 29 return 0; 30 } 31 32 int main() 33 { 34 //创建五个子线程 35 string str1 = "A"; 36 string str2 = "B"; 37 string str3 = "C"; 38 string str4 = "D"; 39 string str5 = "E"; 40 41 HANDLE hThread1 = CreateThread(NULL, 0, Fun, (void*)str1.c_str(), 0, NULL); 42 HANDLE hThread2 = CreateThread(NULL, 0, Fun, (void*)str2.c_str(), 0, NULL); 43 HANDLE hThread3 = CreateThread(NULL, 0, Fun, (void*)str3.c_str(), 0, NULL); 44 HANDLE hThread4 = CreateThread(NULL, 0, Fun, (void*)str4.c_str(), 0, NULL); 45 HANDLE hThread5 = CreateThread(NULL, 0, Fun, (void*)str5.c_str(), 0, NULL); 46 47 //关闭线程 48 CloseHandle(hThread1); 49 CloseHandle(hThread2); 50 CloseHandle(hThread3); 51 CloseHandle(hThread4); 52 CloseHandle(hThread5); 53 54 getchar(); 55 // system("pause"); 56 return 0; 57 }
执行结果:
这是加上Sleep(1);的运行结果,没有加上Sleep(1);的执行结果如下:
从结果我们可以看出如果没有加上Sleep(1),即在离开临界区后进行休眠,其他线程进入临界区的概率会大大降低,原因可能是由于While循环在不停的循环时,其他线程还没有那么快能够进入临界区,因此在这种情况下想让所有的线程都有机会进入临界区,则需要在离开临界区之后做短暂休眠即可。
3、Linux平台
在Linux环境下,没有Windows下的临界区的概念,但是也可以利用互斥量实现该功能。Linux下的API如下,在前面的博文里也有讲到过
1 #include <pthread.h> 2 int pthread_mutexattr_init(pthread_mutexattr_t *attr); /*初始化函数*/ 3 int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);/*去初始化函数*/ 4 5 int pthread_mutex_lock(pthread_mutexattr_t *attr)/*加锁*/ 6 int pthread_mutex_unlock(pthread_mutexattr_t *attr)/*解锁*/
但是两者并不是完全一样的,他们的区别总结如下:
1、临界区只能用于对象在同一进程里线程间的互斥访问;互斥体可以用于对象进程间或线程间的互斥访问。
2、临界区是非内核对象,只在用户态进行锁操作,速度快;互斥体是内核对象,在核心态进行锁操作,速度慢。
3、临界区和互斥体在Windows平台都下可用;Linux下只有互斥体可用。
4、临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。
5、互斥量:为协调共同对一个共享资源的单独访问而设计的。