CRITICAL_SECTION临界
不论是硬件临界资源,还是软件临界资源,多个线程必须互斥地对它进行访问。每个线程中访问临界资源的那段代码称为临界区(Critical Section)。
临界资源是一次仅允许一个线程使用的共享资源。每次只准许一个线程进入临界区,进入后不允许其他线程进入。不论是硬件临界资源,还是软件临界资源,多个线程必须互斥地对它进行访问。
线程进入临界区的调度原则是: ①如果有若干线程要求进入空闲的临界区,一次仅允许一个线程进入。②任何时候,处于临界区内的线程不可多于一个。如已有线程进入自己的临界区,则其它所有试图进入临界区的线程必须等待。③进入临界区的线程要在有限时间内退出,以便其它线程能及时进入自己的临界区。④如果线程不能进入自己的临界区,则应让出CPU,避免线程出现“忙等”现象。
如果有多个线程试图同时访问临界区,那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开。临界区在被释放后,其他线程可以继续抢占,并以此达到用原子方式操作共享资源的目的。
临界区在使用时以CRITICAL_SECTION结构对象保护共享资源,并分别用EnterCriticalSection()和LeaveCriticalSection()函数去标识和释放一个临界区。所用到的CRITICAL_SECTION结构对象必须经过InitializeCriticalSection()的初始化后才能使用,而且必须确保所有线程中的任何试图访问此共享资源的代码都处在此临界区的保护之下。否则临界区将不会起到应有的作用,共享资源依然有被破坏的可能。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
//临界 #include <stdio.h> #include <process.h> #include <windows.h> #include "iostream" using std::cout; using std::endl; CRITICAL_SECTION cpp_cs; unsigned __stdcall Thread1( PVOID pvParm ) { /// 当前线程号 volatile static long lTreadNum = 0; int iCurThread = InterlockedIncrement( &lTreadNum ); for( int i = 0; i < 10; ++ i) { // 进入临界区 EnterCriticalSection(&cpp_cs); // 对需要保护的资源进行操作 cout << "线程" << iCurThread << "打印:" << i << endl; // 没此进入临界区后必须调用离开临界区函数 LeaveCriticalSection(&cpp_cs); } return 0; } //使用TryEnterCriticalSection在获取资源不成功时会立刻返回,这时可以进行一些其它的操作后,再尝试进入 unsigned __stdcall Thread2( PVOID pvParm ) { volatile static long lTreadNum = 0; int iCurThread = InterlockedIncrement( &lTreadNum ); /// 记录尝试进入临界区的次数 int iTryEnterTimes = 0; for( int i = 0; i < 10; ++ i) { /// 进入临界区不成功时,尝试次数加1 while( !TryEnterCriticalSection(&cpp_cs) ) { ++iTryEnterTimes; } cout << "线程" << iCurThread << "打印:" << i << " TryTimes:" << iTryEnterTimes << endl; iTryEnterTimes = 0; LeaveCriticalSection(&cpp_cs); } return 0; } void runThread(unsigned int(__stdcall *ThreadFuc)(void *)) { HANDLE hThread1 = (HANDLE)_beginthreadex(NULL, 0, ThreadFuc, NULL, 0, NULL); HANDLE hThread2 = (HANDLE)_beginthreadex(NULL, 0, ThreadFuc, NULL, 0, NULL); if( hThread1 != NULL ) { WaitForSingleObject(hThread1, INFINITE); CloseHandle(hThread1); } if( hThread2 != NULL ) { WaitForSingleObject(hThread2, INFINITE); CloseHandle(hThread2); } } int main(int argc,char *argv[]) { InitializeCriticalSection(&cpp_cs); //初始化 runThread(Thread1); //运行线程 printf("\n\n\n\n"); runThread(Thread2); DeleteCriticalSection(&cpp_cs); //释放 printf("\n\n\n\n"); //使用旋转锁初始化临界区,可以提高资源使用效率,尽可能使用这种方式进行资源保护 InitializeCriticalSectionAndSpinCount(&cpp_cs, 4000); runThread(Thread1); DeleteCriticalSection(&cpp_cs); return 0; } 运行结果: |
参考资料:百度百科等,Copyright:cpp.cloudcpp.com Share、Open- C/C++程序员之家