所谓临界区就是同一时刻只能有一个线程访问的代码段。处于临界区的代码通常都是需要被多个线程访问,但又只能顺序访问的。
一般就是共享的数据。用于实现顺序访问临界区的方式有多种,互斥量、信号量、事件都可以实现。
下面的方式是采用互斥量实现一个类,比直接使用互斥量方便、直观。
#include <stdio.h> #include <string.h> #include <stdlib.h> #ifndef WIN32 #include <pthread.h> #else #include <windows.h> #endif #ifdef WIN32 typedef HANDLE pthread_mutex_t; #endif class CCriticalSection { public: CCriticalSection(pthread_mutex_t& lock); ~CCriticalSection(); public: static void enterCS(pthread_mutex_t& lock); static void leaveCS(pthread_mutex_t& lock); private: pthread_mutex_t& m_Mutex; // Alias name of the mutex to be protected int m_iLocked; // Locking status // CGuard& operator=(const CGuard&); }; // // Automatically lock in constructor // 这里需要提供一个全局的互斥量为参数 // 临界区是为了实现多个线程顺序访问共享数据,显然应该要有一个 // 多个线程可以访问的变量才能实现,如果在构造函数中创建一个互斥量, // 这个互斥量对其它线程来说是不可见的,当然就无法实现与其它线程的互斥访问 CCriticalSection::CCriticalSection(pthread_mutex_t& lock): m_Mutex(lock), m_iLocked() { #ifndef WIN32 m_iLocked = pthread_mutex_lock(&m_Mutex); #else m_iLocked = WaitForSingleObject(m_Mutex, INFINITE); #endif } // Automatically unlock in destructor CCriticalSection::~CCriticalSection() { #ifndef WIN32 if (0 == m_iLocked) pthread_mutex_unlock(&m_Mutex); #else if (WAIT_FAILED != m_iLocked) ReleaseMutex(m_Mutex); #endif } //相当于WaitForSingleObject更直观的表述 void CCriticalSection::enterCS(pthread_mutex_t& lock) { #ifndef WIN32 pthread_mutex_lock(&lock); #else WaitForSingleObject(lock, INFINITE); #endif } //相当于ReleaseMutex更直观的表述 void CCriticalSection::leaveCS(pthread_mutex_t& lock) { #ifndef WIN32 pthread_mutex_unlock(&lock); #else ReleaseMutex(lock); #endif } pthread_mutex_t g_mutex = CreateMutex(NULL, FALSE, NULL); DWORD WINAPI worker(LPVOID lpParameter) { DWORD id = GetCurrentThreadId(); while (1) { CCriticalSection cs(g_mutex); //作用范围是本次循环 printf("id: %u\n", id); } } int main(int argc, char **argv) { for (int i=0; i<3; i++) CreateThread(NULL, 0, worker, NULL, 0, NULL); Sleep(20000); return 0; }
如果没有互斥处理输出可能是这样的:
加上互斥处理后,输出类似这样:
三个线程按顺序获得了锁,具有均等的运行机会。