设为首页 加入收藏

TOP

线程控制(三)
2019-09-14 00:52:38 】 浏览:89
Tags:线程 控制
段时间内都不会调用前面两张图中的取消点函数,那么可以调用pthread_testcancel在线程中添加自己的取消点。
调用pthread_testcancel时,如果有某个取消请求处于挂起状态,且可取消状态为ENABLE,那么线程就会被取消。

void pthread_testcancel();

使用线程取消的风险

当线程响应取消请求而终止时,主要面临的两大风险:

  • 线程里面的锁可能没有unlock,有可能导致死锁
  • 线程申请的资源(如堆内存)没有释放

下面是一段由pthread_cancel引起的死锁范例代码。

#include <pthread.h>
#include <stdio.h>

static pthread_cond_t  cond;
static pthread_mutex_t mutex;

void *thread0(void *arg)
{ 
    pthread_mutex_lock(&mutex);    
    printf("thread 0 lock sucess\n");
    pthread_cond_wait(&cond, &mutex); //主线程发出取消请求时,thread1阻塞于slepp(2),thread0阻塞于此取消点,导致thread0未解锁mutex就终止
    printf("thread 0 pthread_cond_wait return\n"); 
    pthread_mutex_unlock(&mutex); 
    
    pthread_exit(0);
}

void *thread1(void *arg)
{
    sleep(2);   
    
    printf("thread 1 start lock\n");
    pthread_mutex_lock(&mutex);       //thread0终止约1S后,thread1执行到此,由于mutex已加锁,也没有其他地方能够对其解锁,从而导致死锁
    printf("thread 1 lock sucess\n");      
    pthread_cond_signal(&cond);    
    pthread_mutex_unlock(&mutex); 
    
    pthread_exit(0);  
}

int main()
{     
    pthread_t tid[2];
    
    pthread_cond_init(&cond, NULL);
    pthread_mutex_init(&mutex, NULL);
    
    pthread_create(&tid[0], NULL, thread0, NULL);
    pthread_create(&tid[1], NULL, thread1, NULL);

    sleep(1);  
    pthread_cancel(tid[0]);
    printf("main thread request cancel thread 0\n");

    pthread_join(tid[0], NULL);
    pthread_join(tid[1], NULL);
  
    pthread_cond_destroy(&cond);
    pthread_mutex_destroy(&mutex);
    
    return 0;
}

线程清理程序

可以使用线程清理程序来解决线程取消的风险问题。线程可以安排它退出时需要调用的函数,这样的函数称为线程清理程序。
一个线程可以注册多个清理程序,处理程序记录在栈中,也就是说,它们的执行顺序和注册顺序是相反的。

void pthread_cleanup_push(void (*routine)(void *), void *arg);
void pthread_cleanup_pop(int execute);

当线程执行以下动作时,清理程序是由pthread_cleanup_push函数调度的,调用时只有一个参数arg:

  • 调用pthread_exit结束线程
  • 响应pthread_cancel取消请求
  • 用非零execute参数调用pthread_cleanup_pop

注意:如果线程以return方式终止,线程清理程序不会被调用。

不管发生上述哪种情况,pthread_cleanup_pop都将删除上次pthread_cleanup_push登记的线程清理程序。
这两个函数有一个限制,由于它们经常实现为宏,所以必须在与线程启动例程相同的作用域中以配对的方式使用,否则,可能会产生编译错误。

回到线程取消的风险问题上来,我们只需要在线程清理程序中解锁和释放资源,并在线程启动例程的第一步就注册清理程序
这样,当线程因响应取消请求而终止时,线程清理程序就会得以执行。

#include <pthread.h>
#include <stdio.h>

static pthread_cond_t  cond;
static pthread_mutex_t mutex;

void cleanup(void *arg)
{
    pthread_mutex_unlock(&mutex); 
    printf("mutex unlock in cleanup\n");
}

void *thread0(void *arg)
{
    pthread_cleanup_push(cleanup, NULL); //注册线程清理程序进行解锁
    
    pthread_mutex_lock(&mutex);    
    printf("thread 0 lock sucess\n");
    pthread_cond_wait(&cond, &mutex);    //主线程发出取消请求时,thread1阻塞于slepp(2),thread0阻塞于此取消点
    printf("thread 0 pthread_cond_wait return\n"); 
    pthread_mutex_unlock(&mutex); 
    
    pthread_cleanup_pop(0);
    pthread_exit(0);
}

void *thread1(void *arg)
{
    sleep(2);   
    
    printf("thread 1 start lock\n");
    pthread_mutex_lock(&mutex);          //thread0终止约1S后,thread1执行到此
    printf("thread 1 lock sucess\n");      
    pthread_cond_signal(&cond);    
    pthread_mutex_unlock(&mutex); 
    
    pthread_exit(0);  
}

int main()
{     
    pthread_t tid[2];
    
    pthread_cond_init(&cond, NULL);
    pthread_mutex_init(&mutex, NULL);
    
    pthread_create(&tid[0], NULL, thread0, NULL);
    pthread_create(&ti
首页 上一页 1 2 3 4 下一页 尾页 3/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇RedHat Linux-配置YUM仓库 下一篇解锁HMC8及HMC9的root用户

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目