死锁就是不同的程序在运行时因为某种原因发生了阻塞,进而导致程序不能正常运行。阻塞程序的原因通常都是由于程序没有正确使用临界资源。

我们举个日常生活中的例子来比喻死锁。我们把马路上行驶的汽车比作运行着的程序,把马路比作临界资源,如果有两辆汽车相互碰撞,就会把车停在马路上,这样的话他们一直占用着马路这个临界资源。其它的汽车不能正常通过马路,于是整条路上的汽车都无法在马路上正常行驶,马路也被汽车堵的水泄不通。整个交通都瘫痪了,这就是“死锁”。造成死锁的原因就是发生车祸的汽车占用了马路这种临界资源,以至于其它汽车无法在马路上正常行驶。

在实际的程序中造成死锁的原因有两种:

1 同一个线程对已经加锁的互斥量再次加锁;

2 线程A对互斥量一加锁,同时等待互斥量二被解锁;而此时,线程B对互斥量二加锁,同时等待互斥量一被解锁;

首先来看第一种现象:

int value=0;

pthread_mutex_t mutex_value_tmp1=PTHREAD_MUTEX_INITIALIZER;

void read_data(){

printf("data=%d\n",value);

printf("end reading data\n");

}

void threading_func1(){

int i=0;

int res=0;

pthread_t thread_id;

thread_id=pthread_self();

printf("Thread id :%d\n",thread_id);

while(i<4){

res=pthread_mutex_lock(&mutex_value_tmp1);  #第一次加锁

if (res !=0){

printf("thread mutex failed\n");

}

read_data();

res=pthread_mutex_lock(&mutex_value_tmp1);  #第二次加锁

if (res !=0){

printf("thread mutex failed\n");

}

res=pthread_mutex_unlock(&mutex_value_tmp1);  #释放锁;

printf("res=%d\n",res);

if (res !=0){

printf("mutex unlock failed\n");

}

Sleep(2000);

}

pthread_exit((void *)2);

}

结果执行如下:

当线程2再次执行的时候,由于无法获取锁,因此发生死锁

linux c编程:线程互斥二 线程死锁-LMLPHP

这种情况下为了避免阻塞。需要用到pthread_mutex_tryloc。

函数pthread_mutex_trylock是pthread_mutex_lock的非阻塞版本。如果mutex参数所指定的互斥锁已经被锁定的话,调用pthread_mutex_trylock函数不会阻塞当前线程,而是立即返回一个值来描述互斥锁的状况。将上面代码中的pthread_mutex_lock全部替换为pthread_mutex_trylock。在来看下运行结果:

每当重复加锁的时候都会发生加锁失败,但是不会发生死锁。

linux c编程:线程互斥二 线程死锁-LMLPHP

下面来看下第二种情况:

代码如下:

int value=0;

pthread_mutex_t mutex_value_tmp1=PTHREAD_MUTEX_INITIALIZER;

pthread_mutex_t mutex_value_tmp2=PTHREAD_MUTEX_INITIALIZER;

void read_data(){

printf("data=%d\n",value);

printf("end reading data\n");

}

void write_data(){

value+=1;

printf("data=%d\n",value);

printf("end writing data\n");

}

void threading_func1(){

int i=0;

int res=0;

pthread_t thread_id;

thread_id=pthread_self();

printf("Thread id :%d\n",thread_id);

while(i++<4){

res=pthread_mutex_trylock(&mutex_value_tmp1);

if (res !=0){

printf("thread mutex1 failed\n");

}

read_data();

res=pthread_mutex_trylock(&mutex_value_tmp2);

if (res !=0){

printf("thread mutex2 failed\n");

}

res=pthread_mutex_unlock(&mutex_value_tmp2);

if (res !=0){

printf("mutex2 unlock failed\n");

}

res=pthread_mutex_unlock(&mutex_value_tmp1);

if (res !=0){

printf("mutex1 unlock failed\n");

}

Sleep(2000);

}

pthread_exit((void *)2);

}

void threading_func2(){

int i=0;

int res=0;

pthread_t thread_id;

thread_id=pthread_self();

printf("Thread id :%d\n",thread_id);

while(i++<4){

res=pthread_mutex_lock(&mutex_value_tmp2);

if (res !=0){

printf("thread mutex2 failed\n");

}

write_data();

res=pthread_mutex_lock(&mutex_value_tmp1);

if (res !=0){

printf("thread mutex1 failed\n");

}

res=pthread_mutex_unlock(&mutex_value_tmp1);

if (res !=0){

printf("mutex1 unlock failed\n");

}

res=pthread_mutex_unlock(&mutex_value_tmp2);

if (res !=0){

printf("mutex2 unlock failed\n");

}

Sleep(2000);

}

pthread_exit((void *)2);

}

int main()

{

pthread_t tid1,tid2;

int res;

void *tret;

pthread_mutex_init(&mutex_value_tmp1,NULL);

pthread_mutex_init(&mutex_value_tmp2,NULL);

pthread_create(&tid1,NULL,threading_func1,NULL);

pthread_create(&tid2,NULL,threading_func2,NULL);

pthread_join(tid1,&tret);

printf("thread 1 exit code %ld\n",(long)tret);

pthread_join(tid2,&tret);

printf("thread 2 exit code %ld\n",(long)tret);

res=pthread_mutex_destroy(&mutex_value_tmp1);

if (res!=0){

printf("mutex can't be destroyed");

}

return 0;

}

运行结果如下:从下面的程序运行结果中可以看到,线程1锁住了互斥量一,同时等待互斥量二;而线程2锁住了互斥量二,同时等待互斥量一。这样便造成了死锁,进而引起了程序运行错误。在写代码的时候应该避免这类用法

linux c编程:线程互斥二 线程死锁-LMLPHP

05-27 07:40