Linux可复入的互斥量pthread_mutex_t

互斥量可重入(可复入)的概念是:同一个线程,进入一互斥量后,不出此互斥量而再次进入此互斥量,线程不会死等。

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;
};