muduo::thread类分析

在看源代码前,先学习一个关键字:__thread。

线程共享进程的数据,如果想要每个线程都有一份独立的数据,那么可以使用__thread关键字修饰数据。 __thread只能用于修饰POD类型的数据,不能修饰class,因为它无法调用构造函数和析构函数。__thread可以修饰全局变量、函数内的静态变量,不能修饰函数内的局部变量或class的普通成员变量。

在muduo/base/thread.{h, cc}中实现了线程的封装。thread的封装和一个命名空间muduo::CurrentThread紧密相关,在这个空间中定义了和线程相关的属性,这些属性如下:

  extern __thread int t_cachedTid;
  extern __thread char t_tidString[32];
  extern __thread int t_tidStringLength;
  extern __thread const char* t_threadName;

t_cachedTid表示线程的真实id。 POSIX的thread库提供了pthread_self获取当前线程的标识符,类型为pthread_t,这是一个结构体,用起来不便。线程的真实id是一个整数,可以通过系统调用syscall(SYS_gettid)获得,在muduo中封装为gettid()函数。调用系统调用开销比较大,因此可以使用一个变量t_cachedTid来存储,在线程第一次使用tid时通过系统调用获得,存储在t_cacheTid中,以后使用时不再需要系统调用了。

t_tidString[32] 用string类型表示tid,便于输出日志。

t_tidStringLength string类型tid的长度。

t_threadName 线程的名字。

命名空间muduo::CurrentThread还声明了一些函数,用来获取上述线程的属性,这些函数在thread.cc中实现。

thread类的类图如下:

ThreadFunc类型为:

typedef boost::function<void ()> ThreadFunc;

即为线程执行的函数对象。

numCreated_是一个静态变量,类型为AtomicInt32(定义在Atomic.h),用来表示第几次创建线程实例,在记录日志时可以记录为:线程名+numCreated_ 。

析构函数如下:

Thread::~Thread()
{
  if (started_ && !joined_)
  {
    pthread_detach(pthreadId_);
  }
}

可以看出没有在析构函数join,即thread的析构不会等待线程的结束。如果thread对象的生命周期长于线程,那么可以通过Thread::join等待线程结束,否则析构时会自动detach线程,避免资源泄露。

其他成员变量很容易从名字看出其意义。

在类thread的实现(thread.cc)中还用到了两个数据结构,一个为ThreadData,用来辅助调用线程执行的函数。另一个为ThreadNameInitializer,为了给线程创建做准备,这个类有个全局实例,会先调用它的构造函数,在构造函数中给线程的创建做好环境准备。其中用到了pthread_atfork(NULL, NULL, &afterFork)。这个函数原型如下:

#include <pthread.h>
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));

这是一个跟进程创建有关的函数,为fork的调用做准备和调用后子进程父进程的初始化。prepare函数在调用fork前执行,parent在调用fork后的父进程中执行,child在调用fork后的子进程中执行。这是假设了当前线程的主线程是由另一个进程创建的。

在实际应用中,多线程时不要调用fork,否则容易出现一些问题。因为fork只能克隆当前线程,却会复制当前进程的所有资源以及其状态,如果复制了一个lock的mutex,却没有复制unlock的线程,那么在给mutex加锁时就会出现死锁。唯一安全的做法是fork后马上调用exec函数。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-08 01:29:12

muduo::thread类分析的相关文章

Android开发之Thread类分析 (转载)

转自:http://blog.csdn.net/llping2011/article/details/9706599 在我们Linux系统中创建线程函数为:pthread_create(),在Android中我们为线程封装了一个类Thread,实际调用的还是pthread_create() 当我们想创建线程的时候,只需要继承于这个Thread类并实现虚函数thread_loop()即可. frameworks/base/include/utils/threads.h class Thread :

android分析之Thread类

线程与线程类要区分开来. 抽象来说,线程是CPU调度的最小单位,但是线程总要执行代码,这个代码就在线程类里说明(即Thread类).无论如何,Thread只是一个类,但其功能就是“启动一个线程,运行用户指定的Runnable”.创建一个线程有两种方式: 继承一个Thread类,实现其run()方法 直接实现Runnable,并用Runnable对象构造Thread对象 这两种方法,最后都是调用VMThread.create(this, stacksize)来真正创建一个线程,线程执行的代码在ru

java基础知识回顾之java Thread类学习(八)--java多线程通信等待唤醒机制经典应用(生产者消费者)

 *java多线程--等待唤醒机制:经典的体现"生产者和消费者模型 *对于此模型,应该明确以下几点: *1.生产者仅仅在仓库未满的时候生产,仓库满了则停止生产. *2.消费者仅仅在有产品的时候才能消费,仓空则等待. *3.当消费者发现仓储没有产品可消费的时候,会唤醒等待生产者生产. *4.生产者在生产出可以消费的产品的时候,应该通知等待的消费者去消费. 下面先介绍个简单的生产者消费者例子:本例只适用于两个线程,一个线程生产,一个线程负责消费. 生产一个资源,就得消费一个资源. 代码如下: pub

java基础知识回顾之java Thread类学习(六)--java多线程同步函数用的锁

1.验证同步函数使用的锁----普通方法使用的锁 思路:创建两个线程,同时操作同一个资源,还是用卖票的例子来验证.创建好两个线程t1,t2,t1线程走同步代码块操作tickets,t2,线程走同步函数封装的代码操作tickets,同步代码块中的锁我们可以指定.假设我们事先不知道同步函数用的是什么锁:如果在同步代码块中指定的某个锁(测试)和同步函数用的锁相同,就不会出现线程安全问题,如果锁不相同,就会发生线程安全问题. 看下面的代码:t1线程用的同步锁是obj,t2线程在操作同步函数的资源,假设不

C++11的thread代码分析

本文分析的是llvm libc++的实现:http://libcxx.llvm.org/ class thread thread类直接包装了一个pthread_t,在linux下实际是unsigned long int. class thread { pthread_t __t_; id get_id() const _NOEXCEPT {return __t_;} } 用了一个std::unique_ptr来包装用户定义的线程函数: 创建线程用的是 template <class _Fp>

Spring源码分析——BeanFactory体系之抽象类、类分析(二)

上一篇分析了BeanFactory体系的2个类,SimpleAliasRegistry和DefaultSingletonBeanRegistry——Spring源码分析——BeanFactory体系之抽象类.类分析(一),今天继续分析. 一.工厂Bean注册支持——FactoryBeanRegistrySupport 废话不多说,直接看我注释的源码: /* * Copyright 2002-2012 the original author or authors. * * Licensed und

性能分析之-- JAVA Thread Dump 分析综述

性能分析之-- JAVA Thread Dump 分析综述 一.Thread Dump介绍 1.1什么是Thread Dump? Thread Dump是非常有用的诊断Java应用问题的工具.每一个Java虚拟机都有及时生成所有线程在某一点状态的thread-dump的能力,虽然各个 Java虚拟机打印的thread dump略有不同,但是大多都提供了当前活动线程的快照,及JVM中所有Java线程的堆栈跟踪信息,堆栈信息一般包含完整的类名及所执行的方法,如果可能的话还有源代码的行数. 1.2 T

java基础知识回顾之java Thread类学习(四)--java多线程安全问题(锁)

上一节售票系统中我们发现,打印出了错票,0,-1,出现了多线程安全问题.我们分析为什么会发生多线程安全问题? 看下面线程的主要代码: @Override public void run() { // TODO Auto-generated method stub while(true){ if(ticket > 0){//当线程0被调起的时候,当执行到这条判断语句的时候,线程1被调起抢了CPU资源,线程0进入冻结状态. try { Thread.sleep(100);//中断当前活跃的线程,或者

JavaSE学习52:细说多线程之Thread类和Runable接口

一线程创建的两种方式比较 线程创建和启动有两种方式,这里只是列出步骤,不再进行详细解释. (1)继承Thread类 class MyThread extends Thread{ public void run(){ ... } } MyThread mt=new MyThread();//创建线程 mt.start();//启动线程 (2)实现Runnable接口 class MyThread implements Runnable{ public void run(){ ... } } MyT