muduo基础库学习--线程封装

  • 线程标识符
    Linux中,每个进程有一个pid, 类型为pid_t, 由getpid()获得;
    Linux下POSIX线程也有id,类型为pthread_t, 由pthread_self()获得,其id由线程库维护,其id空间是各个进程独立的(即不同进程中的线程可能有相同的id)。POSIX线程库的实现也是一个进程;

有时需要从一个进程p1向另外一个进程的线程p2发送信号时,既不能使用p2的pid,更不能使用p2的pthread id, 而只能使用该线程的真实pid,称为tid。由gettid() 可得到tid,但glibc未实现该函数,只能通过Linux系统调用syscall(SYS _gettid)获取。

//CurrentThread.h

// __thread修饰的变量是线程局部存储的
extern __thread int t_cachedTid; //线程真实pid(tid)的缓存
extern __thread char t_tidString[32];//tid的字符串表示形式

//thread.cc
pid_t gettid()
{
  return static_cast<pid_t>(::syscall(SYS_gettid));
}

void CurrentThread::cacheTid()
{
  if (t_cachedTid == 0)
  {
    t_cachedTid = detail::gettid();
    t_tidStringLength = snprintf(t_tidString, sizeof t_tidString, "%5d ", t_cachedTid);
  }
}
  • 缓存tid,以免每次都要getid(),浪费系统资源
  • __thread只能修饰POD(plain old data)类型,即与C兼容的原始数据

//Thread.cc

//用结构体封装了线程的属性和方法,供Thread调用
struct ThreadData
{
  typedef muduo::Thread::ThreadFunc ThreadFunc;
  ThreadFunc func_;
  string name_;
  pid_t* tid_;
  CountDownLatch* latch_;

  ThreadData(ThreadFunc func, const string& name, pid_t* tid,
    			CountDownLatch* latch)
    : func_(std::move(func)),
      name_(name),
      tid_(tid),
      latch_(latch)
  { }

  void runInThread(){
	...	
  }
}

void Thread::start()//创建线程
{
  ...
  if (pthread_create(&pthreadId_, NULL, &detail::startThread, data))
  ...
}

void* startThread(void* obj)//线程函数
{
  ThreadData* data = static_cast<ThreadData*>(obj);
  data->runInThread();
  delete data;
  return NULL;
}

//如果线程tid等于当前进程id,则为主线程
bool CurrentThread::isMainThread()
{
  return tid() == ::getpid();
}

//Thread.cc

void afterFork()
{
  muduo::CurrentThread::t_cachedTid = 0;
  muduo::CurrentThread::t_threadName = "main";
  CurrentThread::tid();
  // no need to call pthread_atfork(NULL, NULL, &afterFork);
}

class ThreadNameInitializer
{
 public:
  ThreadNameInitializer()
  {
    muduo::CurrentThread::t_threadName = "main";
    CurrentThread::tid();
    pthread_atfork(NULL, NULL, &afterFork);
  }
};
  • *int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (child)(void)) 调用fork时,创建子进程前在父进程中会调用prepare,创建子进程成功后,父进程调用parent,子进程调用child。
  • fork可能在主线程或子线程中调用,fork()得到一个新进程,新进程只有一个执行序列,只有一个线程(调用fork的线程被继承下来)。
  • 实际上,对于编写多线程,最好不调用fork().
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值