前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >线程源码分析之cancel.c(基于linuxthreads2.0.1)

线程源码分析之cancel.c(基于linuxthreads2.0.1)

作者头像
theanarkh
发布2019-10-08 17:56:06
4350
发布2019-10-08 17:56:06
举报
文章被收录于专栏:原创分享原创分享

cancel.c实现了线程的是否可取消,取消类型,取消线程,设置线程退出时需要执行的函数列表等功能。

代码语言:javascript
复制
/* Thread cancellation */

#include <errno.h>
#include "pthread.h"
#include "internals.h"
#include "restart.h"

/*
 修改线程的可取消属性。有一个取消点
 取消状态分为可取消,不可取消
    不可取消的时候,收到取消信号,忽略
    可取消的时候,收到取消信号的时候,根据取消类型做处理。
      立即处理
      不立刻处理,到下一个取消点,判定线程的状态的取消类型再处理
 */
int pthread_setcancelstate(int state, int * oldstate)
{
  pthread_t self = thread_self();
  if (state < PTHREAD_CANCEL_ENABLE || state > PTHREAD_CANCEL_DISABLE)
    return EINVAL;
  // 保存旧的状态
  if (oldstate != NULL) *oldstate = self->p_cancelstate;
  // 设置新的状态
  self->p_cancelstate = state;
  // 判断线程是否被取消了,并且当前被设置成可取消状态,并且是需要马上处理的,则直接退出
  if (self->p_canceled &&
      self->p_cancelstate == PTHREAD_CANCEL_ENABLE &&
      self->p_canceltype == PTHREAD_CANCEL_ASYNCHRONOUS)
    pthread_exit(PTHREAD_CANCELED);
  return 0;
}
// 见上一个函数
int pthread_setcanceltype(int type, int * oldtype)
{
  pthread_t self = thread_self();
  if (type < PTHREAD_CANCEL_DEFERRED || type > PTHREAD_CANCEL_ASYNCHRONOUS)
    return EINVAL;
  if (oldtype != NULL) *oldtype = self->p_canceltype;
  self->p_canceltype = type;
  if (self->p_canceled &&
      self->p_cancelstate == PTHREAD_CANCEL_ENABLE &&
      self->p_canceltype == PTHREAD_CANCEL_ASYNCHRONOUS)
    pthread_exit(PTHREAD_CANCELED);
  return 0;
}
// 给线程发送取消请求,线程收到该信号是否处理,怎么处理取决于线程本身对于取消的相关配置
int pthread_cancel(pthread_t thread)
{
  thread->p_canceled = 1;
  kill(thread->p_pid, PTHREAD_SIG_CANCEL);
  return 0;
}
// 设置一个取消点
void pthread_testcancel(void)
{
  pthread_t self = thread_self();
  // 判断线程是不是已经被取消,并且是可取消的,则退出
  if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE)
    pthread_exit(PTHREAD_CANCELED);
}
// 链表中新增一个clean函数
void _pthread_cleanup_push(struct _pthread_cleanup_buffer * buffer,
			   void (*routine)(void *), void * arg)
{
  pthread_t self = thread_self();
  buffer->routine = routine;
  buffer->arg = arg;
  // 头插法
  buffer->prev = self->p_cleanup;
  self->p_cleanup = buffer;
}
// 删除一个clean节点,execute判断是否需要执行
void _pthread_cleanup_pop(struct _pthread_cleanup_buffer * buffer,
			  int execute)
{
  pthread_t self = thread_self();
  if (execute) buffer->routine(buffer->arg);
  self->p_cleanup = buffer->prev;
}
// 新增一个clean节点,保存旧的取消类型,设置新的取消类型为PTHREAD_CANCEL_DEFERRED
void _pthread_cleanup_push_defer(struct _pthread_cleanup_buffer * buffer,
				 void (*routine)(void *), void * arg)
{
  pthread_t self = thread_self();
  buffer->routine = routine;
  buffer->arg = arg;
  buffer->canceltype = self->p_canceltype;
  buffer->prev = self->p_cleanup;
  self->p_canceltype = PTHREAD_CANCEL_DEFERRED;
  self->p_cleanup = buffer;
}

// 和上面的函数配套。删除一个clean节点,execute控制是否需要执行删除的这个节点,恢复线程的取消类型,是一个有取消点的函数
void _pthread_cleanup_pop_restore(struct _pthread_cleanup_buffer * buffer,
				  int execute)
{
  pthread_t self = thread_self();
  if (execute) buffer->routine(buffer->arg);
  self->p_cleanup = buffer->prev;
  self->p_canceltype = buffer->canceltype;
  if (self->p_canceled &&
      self->p_cancelstate == PTHREAD_CANCEL_ENABLE &&
      self->p_canceltype == PTHREAD_CANCEL_ASYNCHRONOUS)
    pthread_exit(PTHREAD_CANCELED);
}
// 线程退出的时候(pthread_exit)调用执行clean链表的节点
void __pthread_perform_cleanup(void)
{
  pthread_t self = thread_self();
  struct _pthread_cleanup_buffer * c;
  for (c = self->p_cleanup; c != NULL; c = c->prev) c->routine(c->arg);
}

#ifndef PIC
/* We need a hook to force the cancelation wrappers to be linked in when
   static libpthread is used.  */
extern const int __pthread_provide_wrappers;
static const int * const __pthread_require_wrappers =
  &__pthread_provide_wrappers;
#endif
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-10-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 编程杂技 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档