pthread_cancel的带来的一个死锁问题(验证)

来源:互联网 发布:织梦5.7sp2最新漏洞 编辑:程序博客网 时间:2024/06/05 08:13

代码来自:http://blog.csdn.net/wwyyxx26/article/details/9018473
如下:

test_deadlock.c

#include <unistd.h>#include <pthread.h>#include <stdio.h>#include <stdlib.h>pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;pthread_cond_t cond = PTHREAD_COND_INITIALIZER;void* thread0( void* arg ){    printf( "T0:Enter\n" );    printf( "T0:Before lock\n" );    pthread_mutex_lock(&mutex);    printf( "T0:Before pthread_cond_wait\n" );    pthread_cond_wait(&cond,&mutex);    printf( "T0:After pthread_cond_wait\n" );    pthread_mutex_unlock(&mutex);    printf( "T0:Exit\n" );    return NULL;//pthread_exit(NULL);}void* thread1( void* arg ){    printf( "T1:Enter\n" );    sleep(10);    printf( "T1:After Sleep\n" );    int err = pthread_mutex_trylock(&mutex);    if( err == 0 )    {        printf( "T1:Acquire Lock Success\n" );    }    else    {        printf( "T1:Acquire Lock Fail\n" );        pthread_exit(NULL);    }    printf( "T1:Before ptread_mutex_broadcast\n" );    pthread_cond_signal(&cond);    printf( "T1:After pthread_mutex_broadcast\n" );    pthread_mutex_unlock(&mutex);    printf( "T1:Exit\n" );    return NULL;//pthread_exit(NULL);}int main(){    pthread_t tid[2];    if( pthread_create(&tid[0],NULL,&thread0,NULL) != 0 )    {        exit(1);    }    if( pthread_create(&tid[1],NULL,&thread1,NULL) != 0 )    {        exit(1);    }    sleep(5); //不加这句有可能出现不死锁的情况    printf( "Main:Before pthread_cancel tid[0]\n" );    pthread_cancel(tid[0]);    printf( "Main:After pthread_cancel tid[0]\n" );    printf( "Main:Before pthread_join tid[0]\n" );    pthread_join(tid[0],NULL);    printf( "Main:After pthread_join tid[0]\n" );    printf( "Main:Before pthread_join tid[1]\n" );    pthread_join(tid[1],NULL);    printf( "Main:After pthread_join tid[1]" );    pthread_mutex_destroy(&mutex);    pthread_cond_destroy(&cond);    return 0;}

相对于原文中的做出了一点修改
把thread1中的pthread_mutex_lock 修改为pthread_mutex_trylock,pthread_cond_broadcast修改为pthread_cond_signal
编译:
CentOS 6.3 64-bit
gcc test_deadlock.c -lpthread -o test

在运行测试时,都是按照预期出现了死锁,死锁原因在原文中也说得很清楚,就是在thread0在cancellation point(pthread_cond_wait)时,对mutex又加上了锁,thread1这时从sleep中苏醒,再次去acquire mutex,这时就出现了死锁。
(在代码中把thread1中pthread_mutex_trylock恢复为pthread_mutex_lock才会出现死锁,这里的现象为acquire mutex失败线程直接退出)。
正常情况下:
pthread_mutex_lock ->pthread_cond_wait->pthread_mutex_unlock
相当于:pthread_mutex_lock->(pthread_mutex_unlock->pthread_mutex_lock)->pthread_mutex_unlock
在pthread_cancel调用以后,在pthread_cond_wait中的cleanup中会将mutex重新上锁。

POSIX cancellation points参见:
http://stackoverflow.com/questions/433989/posix-cancellation-points
文中提到了pthread_cond_wait,如果thread0是在 pthread_cond_wait这个取消点退出的话,这是会出现死锁的情况。

由于pthread_cond_wait最后是调用的是pthread_mutex_lock,推断pthread_mutex_lock才是真正意义上的cancellation point

测试:
在main线程pthread_cancel前取消sleep(5); 这样在运行时就可能会出现thread0运行至pthread_cond_wait前main thread先运行至pthread_cancel,测试发现会有一定几率(取决于main线程和thread0切换)出现mutex不死锁的情况(并未输出”Before pthread_cond_wait”)

结论:
pthread_mutex_lock也是POSIX cancellation point,pthread_cond_wait因为调用pthread_mutex_lock也成为了 cancellation point.

0 0
原创粉丝点击