互斥量可重入(可复入)的概念是:同一个线程,进入一互斥量后,不出此互斥量而再次进入此互斥量,线程不会死等。
pthread_mutex_init调用时第二个参数传入NULL,即为默认的mutex初始化方式。请记住,这种默认的初始化的方式,生成的是不可重入的互斥量,即同线程重复进入会死等(或叫死锁)。这与Windows上InitializeCriticalSection初始化恰相反。
要pthread_mutex_t可重入,需要使用PTHREAD_MUTEX_RECURSIVE_NP参数,具体见本文后所附源码。
本人已抽象出跨平台的互斥量源码库,其中的互斥量都是可重入的,在Linux和Windows上都可以统一调用,先说使用举例。
定义:
1 | WhMutex mutex_; |
初始化:
1 | whMutexInit(&mutex_); |
反初始化:
1 | whMutexFini(&mutex_); |
当要把一段代码设为临界段时:
1 2 3 4 5 | { WhMutexGuard guard(&mutex_); // your critical section code here. int i; } |
以下是抽象互斥量库源码(直接复制过去就可编译):
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 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | #ifdef WIN32 #ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS #endif #include <winsock2.h> #include <process.h> typedef int socklen_t; #define WH_INVALID_SOCKET INVALID_SOCKET #define whCloseSocket(_socket) closesocket(_socket) #define whSleep(_secs) Sleep((_secs) * 1000) #define WhThreadHandle HANDLE #define WH_INVALID_THREAD (HANDLE)0 #define WH_THREAD_DEF(_proc, _arg) unsigned __stdcall _proc(void *_arg) #define WH_THREAD_PREPROCESS #define whThreadCreate(_handle, _loop, _param) _handle = (WhThreadHandle)_beginthreadex(NULL, 0, _loop, _param, 0, NULL) #define whThreadJoin(_handle) WaitForSingleObject(_handle, INFINITE) #define whThreadTerminate(_handle) TerminateThread(_handle, 0) #define WhMutex CRITICAL_SECTION #define whMutexInit(_handle) InitializeCriticalSection(_handle) #define whMutexEnter(_handle) EnterCriticalSection(_handle) #define whMutexLeave(_handle) LeaveCriticalSection(_handle) #define whMutexFini(_handle) DeleteCriticalSection(_handle) #define whGetLastError() WSAGetLastError() #else #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <fcntl.h> #include <netinet/in.h> #include <arpa/inet.h> #include <pthread.h> #include <errno.h> #include <signal.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #define WH_INVALID_SOCKET (~0) #define whCloseSocket(_socket) close(_socket) #define whSleep(_secs) sleep(_secs) #define WhThreadHandle pthread_t #define WH_INVALID_THREAD 0 #define WH_THREAD_DEF(_proc, _arg) void *_proc(void *_arg) #define WH_THREAD_PREPROCESS \ do { \ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); \ } while(0) #define whThreadCreate(_handle, _loop, _param) pthread_create(&_handle, NULL, _loop, _param) #define whThreadJoin(_handle) pthread_join(_handle, NULL) #define whThreadTerminate(_handle) pthread_cancel(_handle) //#define whThreadTerminate(_handle) pthread_kill(_handle,SIGUSR2) struct WhMutexStruct { pthread_mutexattr_t attr_; pthread_mutex_t m_; }; #define WhMutex WhMutexStruct #define whMutexInit(_handle) \ do { \ if (pthread_mutexattr_init(&(_handle)->attr_) != 0) { \ printf("init mutex attr failed.\n"); \ break; \ } \ pthread_mutexattr_settype(&(_handle)->attr_, PTHREAD_MUTEX_RECURSIVE_NP); \ pthread_mutex_init(&(_handle)->m_, &(_handle)->attr_); \ } while (0) #define whMutexEnter(_handle) pthread_mutex_lock(&(_handle)->m_) #define whMutexLeave(_handle) pthread_mutex_unlock(&(_handle)->m_) #define whMutexFini(_handle) \ do { \ pthread_mutex_destroy(&(_handle)->m_); \ pthread_mutexattr_destroy(&(_handle)->attr_); \ } while (0) #define whGetLastError() errno inline void thread_exit_handler(int sig) { printf("signal %d end.", sig); pthread_exit(0); } #endif class WhMutexGuard { public: WhMutexGuard(WhMutex *cs) { m_cs = cs; whMutexEnter(m_cs); } ~WhMutexGuard() { whMutexLeave(m_cs); } WhMutex *m_cs; }; |