多线程时需要注意互斥锁的加锁顺序,否则可能导致死锁,一个简单的例子:
static pthread_mutex_t A, B;
void *printmsg1(void *msg)
{
// 加锁顺序为A、B
pthread_mutex_lock(&A);
pthread_mutex_lock(&B);
printf("printmsg1\n");
pthread_mutex_unlock(&B);
pthread_mutex_unlock(&A); return 0;
}
void *printmsg2(void *msg) {
// 加锁顺序为B、A
pthread_mutex_lock(&B);
pthread_mutex_lock(&A);
printf("printmsg2\n");
pthread_mutex_unlock(&A);
pthread_mutex_unlock(&B);
return 0;
}
int main(int argc, char**argv) {
pthread_t pt1, pt2;
pthread_mutex_init(&A, NULL);
pthread_mutex_init(&B, NULL);
pthread_create(&pt1,0, printmsg1, NULL);
pthread_create(&pt2,0, printmsg2, NULL);
pthread_join(pt1,0);
pthread_join(pt2,0);
pthread_mutex_destroy(&A);
pthread_mutex_destroy(&B);
return 0;
}
在上面这段代码中,线程pt1调用函数printmsg1,线程pt2调用函数printmsg2,有这两个函数中加锁的顺序不一致,就会很容易导致死锁。
假如某个状态,线程pt1调用函数printmsg1,获取了互斥锁A,线程pt2调用函数printmsg2获取了互斥锁B,由于线程pt1无法继续获取锁B,而处于阻塞,同样,线程pt2由于无法获取互斥锁A而进入阻塞,这样两个都阻塞了就会进入死锁。如果两个函数都按照A、B的顺序获取就不会导致这个问题。
同样,信号量也需要特别注意死锁问题:
先说明一下pthread_cond_wait函数:
该函数第一个参数为条件变量指针,第二个为互斥量指针。该函数调用前,需本线程加锁互斥量,加锁状态的时间内函数完成线程加入等待队列操作 ,线程进入等待前函数解锁互斥量。在满足条件离开pthread_cond_wait函数之前重新获得互斥量并加锁,因此,本线程之后需要再次解锁互斥量。
static pthread_mutex_t A, B;
static pthread_cond_t cond;
static int count;
void *f1(void *msg)
{
pthread_mutex_lock(&A);
pthread_mutex_lock(&B);
while (count)
{
pthread_cond_wait(&cond, &B);
}
pthread_mutex_unlock(&B);
pthread_mutex_unlock(&A);
return 0;
}
void *f2(void *msg)
{
pthread_mutex_lock(&A);
pthread_mutex_lock(&B);
count--;
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&B);
pthread_mutex_unlock(&A);
return 0;
}
int main(int argc, char**argv)
{
pthread_t pt1, pt2;
pthread_mutex_init(&A, NULL);
pthread_mutex_init(&B, NULL);
pthread_cond_init(&cond, NULL);
count = 1;
pthread_create(&pt1,0, f1, NULL);
pthread_create(&pt2,0, f2, NULL);
pthread_join(pt1, NULL);
pthread_join(pt2, NULL);
pthread_mutex_destroy(&A);
pthread_mutex_destroy(&B);
pthread_cond_destroy(&cond); return 0;
}
可能出现这样一种情况:
f1由于count =1从而执行函数:
pthread_cond_wait(&cond, &B);
此时虽然会释放了互斥锁B,之后进入阻塞状态,这里需要注意:此时互斥锁A还没有被释放。
而f2执行需要先获取互斥锁A以及锁B,但是虽然B已经被f1释放了,但是A仍然被f1占着,因此f2所在的线程也会阻塞,这样两个线程同时阻塞,就会导致互等的死锁状态。