多线程程序在线程间共享数据时,如果多个线程同时访问共享数据就可能有问题。互斥量是解决多个线程间共享数据的方法之一。
1.互斥量初始化两种方式:
(1)静态初始化
#include <pthread.h> typedef struct my_struct_tag { pthread_mutex_t mutex; /* Protects access to value */ int value; /* Access protected by mutex */ } my_struct_t; my_struct_t data = {PTHREAD_MUTEX_INITIALIZER, 0}; int main (int argc, char *argv[]) { return 0; }
(2)动态初始化
#include <pthread.h> typedef struct my_struct_tag { pthread_mutex_t mutex; /* Protects access to value */ int value; /* Access protected by mutex */ } my_struct_t; int main (int argc, char *argv[]) { my_struct_t *data; data = malloc (sizeof (my_struct_t)); pthread_mutex_init (&data->mutex, NULL); pthread_mutex_destroy (&data->mutex); (void)free (data); return 0; }
2.加锁和解锁
int pthread_mutex_lock(pthread_mutex_t *mutex)
int pthread_mutex_trylock(pthread_mutex_t *mutex)
int pthread_mutex_unlock(pthread_mutex_t *mutex)
3.非阻塞式互斥量锁
int pthread_mutex_trylock(pthread_mutex_t *mutex)
4.使用多个互斥量
使用多个互斥量易发生死锁的问题,如一个线程锁住互斥量A后,加锁互斥量B;同时另一个线程锁住互斥量B而等待互斥量A,则发生死锁现象。针对死锁,有两种解决方法:
(1)固定加锁层次:即所有同时需要加锁互斥量A和互斥量B的代码,必须先加锁A,后加锁B
(2)试加锁和回退:在锁住某个集合中的第一个互斥量后,使用pthread_mutex_trylock来加锁集合中的其他互斥量,如果失败,则将集合中所有已加锁互斥量释放,并重新加锁。
5.链锁
链锁的作用范围互相交叠。当锁住第一个互斥量后,代码进入一个区域,该区域需要另一个互斥量。当锁住另一个互斥量后,第一个互斥量就不再需要,可以释放它了。
链锁在遍历如树型结构或链表结构是很有用。
参考资料:《POSIX多线程程序设计》 pp.39-59