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

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

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

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

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再次执行的时候,由于无法获取锁,因此发生死锁

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

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

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

下面来看下第二种情况:

代码如下:

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锁住了互斥量二,同时等待互斥量一。这样便造成了死锁,进而引起了程序运行错误。在写代码的时候应该避免这类用法

 

posted @   red_leaf_412  阅读(442)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示