互斥锁
-
互斥锁用来保证一段时间内只有一个线程在执行一段代码(保证共享数据的完整性)
-
互斥锁变量
typedef union{ struct __pthread_mutex_s __data; char __size[__SIZEOF_PTHREAD_MUTEX_T]; long int __align; } pthread_mutex_t;
-
互斥锁的生成
/* Initialize a mutex. */ extern int pthread_mutex_init (pthread_mutex_t *__mutex, const pthread_mutexattr_t *__mutexattr) __THROW __nonnull ((1));
用于动态创建一个互斥锁,第一个参数为互斥锁指针,第二个参数为互斥锁属性(通常传
NULL
表示默认属性)
互斥锁属性
-
属性结构
/* Data structures for mutex handling. The structure of the attribute type is not exposed on purpose. */ typedef union{ char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; int __align; } pthread_mutexattr_t;
互斥锁属性使用上面的联合体存放,通过函数
pthread_mutexattr_setpshared()
设置范围属性, -
范围属性
/* Process shared or private flag. */ enum{ PTHREAD_PROCESS_PRIVATE,//同进程中线程同步 #define PTHREAD_PROCESS_PRIVATE PTHREAD_PROCESS_PRIVATE PTHREAD_PROCESS_SHARED //不同进程中的线程同步 #define PTHREAD_PROCESS_SHARED PTHREAD_PROCESS_SHARED };
-
类型属性
通过函数pthread_mutexattr_settype()
(通常使用默认属性PTHREAD_MUTEX_DEFAULT
)/* Mutex types. */ enum{ //缺省值,普通锁,当一个线程加锁以后,其余请求锁的线程将会形成一个等待队列 //并在解锁后按照先后顺序获得锁,资源分配公平 PTHREAD_MUTEX_TIMED_NP, //嵌套锁,允许同一线程对同一锁成功获得多次,并通过多次unlock解锁 //如果是不同线程请求,则在加锁线程解锁时重新竞争 PTHREAD_MUTEX_RECURSIVE_NP, //检错锁,如果同一线程请求同一个锁,则返回EDEALK //否则与普通锁类型动作相同,这样保证当不允许多次时,不会出现最简单的死锁 PTHREAD_MUTEX_ERRORCHECK_NP, //适应锁,动作最简单的类型,仅等待解锁以后重新竞争 PTHREAD_MUTEX_ADAPTIVE_NP #if defined __USE_UNIX98 || defined __USE_XOPEN2K8 , PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_TIMED_NP, PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP, PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP, PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL #endif #ifdef __USE_GNU /* For compatibility. */ , PTHREAD_MUTEX_FAST_NP = PTHREAD_MUTEX_TIMED_NP #endif };
-
Demo
static void init_thread_mutex(void) { pthread_mutexattr_t mutex_attr; //PTHREAD_PROCESS_SHARED pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_PRIVATE); pthread_mutexattr_settype(&mutex_attr,PTHREAD_MUTEX_DEFAULT); //使用上面的属性初始化thread_data_mutex互斥锁 pthread_mutex_init(&thread_data_mutex, &mutex_attr); }
上锁操作
-
加锁
lock ()
、解锁unlock()
、测试加锁trylock()
不论是哪种类型的锁,都不可能被两个不同的线程得到,而必须等待解锁,对于普通锁
和适应锁
,解锁者可以说同进程
内的任何线程,而对于检错锁
必须由加锁者解锁,嵌套锁
也是由加锁者解锁 -
同一进程中的线程,如果枷锁后没有解锁,任何其他线程都无法在获得锁,也就是常说的
死锁
-
上锁
/* Lock a mutex. */ extern int pthread_mutex_lock (pthread_mutex_t *__mutex) __THROWNL __nonnull ((1));
当一个线程执行到
pthread_mutex_lock
处时,如果该锁此时被其他线程线程调用,那么此线程会阻塞,一直等另外一个线程释放锁,然后尝试请求锁。 -
解锁
/* Unlock a mutex. */ extern int pthread_mutex_unlock (pthread_mutex_t *__mutex) __THROWNL __nonnull ((1));
静态锁
-
使用宏
PTHREAD_MUTEX_INITIALIZER
初始化pthread_mutex_t static_data_mutex = PTHREAD_MUTEX_INITIALIZER;
-
静态锁初始化以后就可以直接使用,进行加锁解锁,和动态锁类型,唯一不用的是,当调用
pthread_mutex_trylock()
时,如果正忙则返回EBUSY
而不是挂起等待
锁的销毁
- 销毁锁,意味着释放它所占用的所有资源,且要求锁当前处于开发状态
* Destroy a mutex. */ extern int pthread_mutex_destroy (pthread_mutex_t *__mutex) __THROW __nonnull ((1));
- 在Liunx中,互斥锁不占用任何资源,因此Linux Threads中的
pthread_mutex_destroy()
除了检查锁的状态外没有其他任何操作(忙就返回EBUSY
)
完整Demo
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//自定义数据结构,用于测试
typedef struct ThreadData_t {
pthread_t m_pid;
char* m_threadName;
} ThreadData;
ThreadData threadData;
pthread_mutex_t thread_data_mutex;
pthread_mutex_t static_data_mutex = PTHREAD_MUTEX_INITIALIZER;
static void init_thread_mutex(void) {
pthread_mutexattr_t mutex_attr;
//PTHREAD_PROCESS_SHARED
pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_PRIVATE);
pthread_mutexattr_settype(&mutex_attr,PTHREAD_MUTEX_DEFAULT);
pthread_mutex_init(&thread_data_mutex, &mutex_attr);
}
static void destory_thread_mutex(void) {
pthread_mutex_destroy(&thread_data_mutex);
}
//线程函数routine
static void* test_thread1(void* thread_name) {
fprintf(stderr, "%s try to lock!\n", (char*)thread_name);
pthread_mutex_lock(&thread_data_mutex);
threadData.m_pid = pthread_self();
threadData.m_threadName = (char*)thread_name;
fprintf(stderr, "%s mutex locked! \n", threadData.m_threadName);
sleep(5);
pthread_mutex_unlock(&thread_data_mutex);
return NULL;
}
static void* test_thread2(void* thread_name) {
fprintf(stderr, "%s try to lock!\n", (char*)thread_name);
pthread_mutex_lock(&thread_data_mutex);
threadData.m_pid = pthread_self();
threadData.m_threadName = (char*)thread_name;
fprintf(stderr, "%s mutex locked! \n", threadData.m_threadName);
sleep(6);
pthread_mutex_unlock(&thread_data_mutex);
return NULL;
}
int main(int argc, char** argv) {
pthread_t pid1, pid2;
init_thread_mutex();
if (pthread_create(&pid1, NULL, test_thread1, (void*)"test thread1") != 0) {
fprintf(stderr, "create thread1 failed\n");
return -1;
}
if (pthread_create(&pid2, NULL, test_thread2, (void*)"test thread2") != 0) {
fprintf(stderr, "create thread2 failed\n");
return -1;
}
pthread_join(pid1, NULL);
pthread_join(pid2, NULL);
destory_thread_mutex();
return 0;
}