1.线程标识符

(1)Linux中,每个进程有一个pid,类型pid_t,由getpid()取得。Linux下的POSIX线程也有一个id,类型 pthread_t,由pthread_self()取得,该id由线程库维护,其id空间是各个进程独立的(即不同进程中的线程可能有相同的id)。Linux中的POSIX线程库实现的线程其实也是一个进程(LWP),只是该进程与主进程(启动线程的进程)共享一些资源而已,比如代码段,数据段等。
(2)有时候我们可能需要知道线程的真实pid。比如进程P1要向另外一个进程P2中的某个线程发送信号时,既不能使用P2的pid,更不能使用线程的pthreadid,而只能使用该线程的真实pid,称为tid。
(3)有一个函数gettid()可以得到tid,但glibc并没有实现该函数,只能通过Linux的系统调用syscall来获取。
return syscall(SYS_gettid)

2.Thread类图

typedefboost::function<void ()>ThreadFunc;

_thread,gcc内置的线程局部存储设施
_thread只能修饰POD类型
POD类型(plain old data),与C兼容的原始数据,例如,结构和整型等C语言中的类型是 POD 类型,但带有用户定义的构造函数或虚函数的类则不是

__threadstring t_obj1(“cppcourse”);  //错误,不能调用对象的构造函数

__threadstring* t_obj2 = new string;  //错误,初始化只能是编译期常量

__threadstring* t_obj3 = NULL;  //正确

线程特定属性tsd,可以修饰非POD类型

boost::is_same判断类型是否为同一类型

Thread.h

// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)#ifndef MUDUO_BASE_THREAD_H
#define MUDUO_BASE_THREAD_H#include <muduo/base/Atomic.h>
#include <muduo/base/Types.h>#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
#include <pthread.h>namespace muduo
{class Thread : boost::noncopyable
{public:typedef boost::function<void ()> ThreadFunc;explicit Thread(const ThreadFunc&, const string& name = string());~Thread();void start();int join(); // return pthread_join()bool started() const { return started_; }// pthread_t pthreadId() const { return pthreadId_; }pid_t tid() const { return tid_; }const string& name() const { return name_; }static int numCreated() { return numCreated_.get(); }private:static void* startThread(void* thread);void runInThread();bool       started_;pthread_t  pthreadId_;pid_t      tid_;ThreadFunc func_;string     name_;static AtomicInt32 numCreated_;
};}
#endif

CurrentThread.h

// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)#ifndef MUDUO_BASE_CURRENTTHREAD_H
#define MUDUO_BASE_CURRENTTHREAD_Hnamespace muduo
{
namespace CurrentThread
{// internalextern __thread int t_cachedTid;extern __thread char t_tidString[32];extern __thread const char* t_threadName;void cacheTid();inline int tid(){if (t_cachedTid == 0){cacheTid();}return t_cachedTid;}inline const char* tidString() // for logging{return t_tidString;}inline const char* name(){return t_threadName;}bool isMainThread();
}
}#endif

Thread.cc

// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)#include <muduo/base/Thread.h>
#include <muduo/base/CurrentThread.h>
#include <muduo/base/Exception.h>
//#include <muduo/base/Logging.h>#include <boost/static_assert.hpp>
#include <boost/type_traits/is_same.hpp>#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <linux/unistd.h>namespace muduo
{
namespace CurrentThread
{// __thread修饰的变量是线程局部存储的。__thread int t_cachedTid = 0;     // 线程真实pid(tid)的缓存,// 是为了减少::syscall(SYS_gettid)系统调用的次数// 提高获取tid的效率__thread char t_tidString[32]; // 这是tid的字符串表示形式__thread const char* t_threadName = "unknown";const bool sameType = boost::is_same<int, pid_t>::value;BOOST_STATIC_ASSERT(sameType);
}namespace detail
{pid_t gettid()
{return static_cast<pid_t>(::syscall(SYS_gettid));
}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);}
};ThreadNameInitializer init;
}
}using namespace muduo;void CurrentThread::cacheTid()
{if (t_cachedTid == 0){t_cachedTid = detail::gettid();int n = snprintf(t_tidString, sizeof t_tidString, "%5d ", t_cachedTid);assert(n == 6); (void) n;}
}bool CurrentThread::isMainThread()
{return tid() == ::getpid();
}AtomicInt32 Thread::numCreated_;Thread::Thread(const ThreadFunc& func, const string& n): started_(false),pthreadId_(0),tid_(0),func_(func),name_(n)
{numCreated_.increment();
}Thread::~Thread()
{// no join
}void Thread::start()
{assert(!started_);started_ = true;errno = pthread_create(&pthreadId_, NULL, &startThread, this);if (errno != 0){//LOG_SYSFATAL << "Failed in pthread_create";}
}int Thread::join()
{assert(started_);return pthread_join(pthreadId_, NULL);
}void* Thread::startThread(void* obj)
{Thread* thread = static_cast<Thread*>(obj);thread->runInThread();return NULL;
}void Thread::runInThread()
{tid_ = CurrentThread::tid();muduo::CurrentThread::t_threadName = name_.c_str();try{func_();muduo::CurrentThread::t_threadName = "finished";}catch (const Exception& ex){muduo::CurrentThread::t_threadName = "crashed";fprintf(stderr, "exception caught in Thread %s\n", name_.c_str());fprintf(stderr, "reason: %s\n", ex.what());fprintf(stderr, "stack trace: %s\n", ex.stackTrace());abort();}catch (const std::exception& ex){muduo::CurrentThread::t_threadName = "crashed";fprintf(stderr, "exception caught in Thread %s\n", name_.c_str());fprintf(stderr, "reason: %s\n", ex.what());abort();}catch (...){muduo::CurrentThread::t_threadName = "crashed";fprintf(stderr, "unknown exception caught in Thread %s\n", name_.c_str());throw; // rethrow}
}

Thread_test.cc

#include <muduo/base/Thread.h>
#include <muduo/base/CurrentThread.h>#include <string>
#include <boost/bind.hpp>
#include <stdio.h>void threadFunc()
{printf("tid=%d\n", muduo::CurrentThread::tid());
}void threadFunc2(int x)
{printf("tid=%d, x=%d\n", muduo::CurrentThread::tid(), x);
}class Foo
{public:explicit Foo(double x): x_(x){}void memberFunc(){printf("tid=%d, Foo::x_=%f\n", muduo::CurrentThread::tid(), x_);}void memberFunc2(const std::string& text){printf("tid=%d, Foo::x_=%f, text=%s\n", muduo::CurrentThread::tid(), x_, text.c_str());}private:double x_;
};int main()
{printf("pid=%d, tid=%d\n", ::getpid(), muduo::CurrentThread::tid());muduo::Thread t1(threadFunc);t1.start();t1.join();muduo::Thread t2(boost::bind(threadFunc2, 42),"thread for free function with argument");t2.start();t2.join();Foo foo(87.53);muduo::Thread t3(boost::bind(&Foo::memberFunc, &foo),"thread for member function without argument");t3.start();t3.join();muduo::Thread t4(boost::bind(&Foo::memberFunc2, boost::ref(foo), std::string("Shuo Chen")));t4.start();t4.join();printf("number of created threads %d\n", muduo::Thread::numCreated());
}

3.pthread_atfork

(1)#include <pthread.h>

(2)intpthread_atfork(void (*prepare)(void), void(*parent)(void), void (*child)(void));
(3)调用fork时,内部创建子进程前在父进程中会调用prepare,内部创建子进程成功后,父进程会调用parent ,子进程会调用child
(4)fork可能是在主线程中调用,也可能是在子线程中调用
(5)fork得到一个新进程,新进程只有一个执行序列,只有一个线程(调用fork的线程被继承下来)

1.死锁示例

// 一个在多线程程序里fork造成死锁的例子
// 一个输出示例:
/*pid = 19445 Entering main ...
pid = 19445 begin doit ...
pid = 19447 begin doit ...
pid = 19445 end doit ...
pid = 19445 Exiting main ...父进程在创建了一个线程,并对mutex加锁,
父进程创建一个子进程,在子进程中调用doit,由于子进程会复制父进程的内存,这时候mutex处于锁的状态,
父进程在复制子进程的时候,只会复制当前线程的执行状态,其它线程不会复制。因此子进程会处于死锁的状态。
*/
#include <stdio.h>
#include <time.h>
#include <pthread.h>
#include <unistd.h>pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;void* doit(void* arg)
{printf("pid = %d begin doit ...\n",static_cast<int>(getpid()));pthread_mutex_lock(&mutex);struct timespec ts = {2, 0};nanosleep(&ts, NULL);pthread_mutex_unlock(&mutex);printf("pid = %d end doit ...\n",static_cast<int>(getpid()));return NULL;
}int main(void)
{printf("pid = %d Entering main ...\n", static_cast<int>(getpid()));pthread_t tid;pthread_create(&tid, NULL, doit, NULL);struct timespec ts = {1, 0};nanosleep(&ts, NULL);if (fork() == 0){doit(NULL);}pthread_join(tid, NULL);printf("pid = %d Exiting main ...\n",static_cast<int>(getpid()));return 0;
}

2.无死锁

#include <stdio.h>
#include <time.h>
#include <pthread.h>
#include <unistd.h>pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;void* doit(void* arg)
{printf("pid = %d begin doit ...\n",static_cast<int>(getpid()));pthread_mutex_lock(&mutex);struct timespec ts = {2, 0};nanosleep(&ts, NULL);pthread_mutex_unlock(&mutex);printf("pid = %d end doit ...\n",static_cast<int>(getpid()));return NULL;
}void prepare(void)
{pthread_mutex_unlock(&mutex);
}void parent(void)
{pthread_mutex_lock(&mutex);
}int main(void)
{pthread_atfork(prepare, parent, NULL);printf("pid = %d Entering main ...\n", static_cast<int>(getpid()));pthread_t tid;pthread_create(&tid, NULL, doit, NULL);struct timespec ts = {1, 0};nanosleep(&ts, NULL);if (fork() == 0){doit(NULL);}pthread_join(tid, NULL);printf("pid = %d Exiting main ...\n",static_cast<int>(getpid()));return 0;
}

3.pthread_atfork示例

#include <stdio.h>
#include <time.h>
#include <pthread.h>
#include <unistd.h>void prepare(void)
{printf("pid = %d prepare ...\n", static_cast<int>(getpid()));
}void parent(void)
{printf("pid = %d parent ...\n", static_cast<int>(getpid()));
}void child(void)
{printf("pid = %d child ...\n", static_cast<int>(getpid()));
}int main(void)
{printf("pid = %d Entering main ...\n", static_cast<int>(getpid()));pthread_atfork(prepare, parent, child);fork();printf("pid = %d Exiting main ...\n",static_cast<int>(getpid()));return 0;
}

13muduo_base库源码分析(四)相关推荐

  1. 【投屏】Scrcpy源码分析四(最终章 - Server篇)

    Scrcpy源码分析系列 [投屏]Scrcpy源码分析一(编译篇) [投屏]Scrcpy源码分析二(Client篇-连接阶段) [投屏]Scrcpy源码分析三(Client篇-投屏阶段) [投屏]Sc ...

  2. 《微信小程序-进阶篇》Lin-ui组件库源码分析-列表组件List(一)

    大家好,这是小程序系列的第二十篇文章,在这一个阶段,我们的目标是 由简单入手,逐渐的可以较为深入的了解组件化开发,从本文开始,将记录分享lin-ui的源码分析,期望通过对lin-ui源码的学习能加深组 ...

  3. Android主流三方库源码分析(九、深入理解EventBus源码)

    一.EventBus使用流程概念 1.Android事件发布/订阅框架 2.事件传递既可用于Android四大组件间通信 3.EventBus的优点是代码简洁,使用简单,事件发布.订阅充分解耦 4.首 ...

  4. ABP源码分析四十七:ABP中的异常处理

    ABP源码分析四十七:ABP中的异常处理 参考文章: (1)ABP源码分析四十七:ABP中的异常处理 (2)https://www.cnblogs.com/1zhk/p/5538983.html (3 ...

  5. gSOAP 源码分析(四)

    gSOAP 源码分析(四) 2012-6-2 邵盛松 前言 本文主要说明gSOAP中对Client的认证分析 gSOAP中包含了HTTP基本认证,NTLM认证等,还可以自定义SOAP Heard实现认 ...

  6. Spring 源码分析(四) ——MVC(二)概述

    随时随地技术实战干货,获取项目源码.学习资料,请关注源代码社区公众号(ydmsq666) from:Spring 源码分析(四) --MVC(二)概述 - 水门-kay的个人页面 - OSCHINA ...

  7. surprise库源码分析

    最近工作上需要使用到协同过滤,来计算相似度,因此根据https://blog.csdn.net/weixin_43849063/article/details/111500236的步骤对surpris ...

  8. 【转】ABP源码分析四十七:ABP中的异常处理

    ABP 中异常处理的思路是很清晰的.一共五种类型的异常类. AbpInitializationException用于封装ABP初始化过程中出现的异常,只要抛出AbpInitializationExce ...

  9. 【转】ABP源码分析四:Configuration

    核心模块的配置 Configuration是ABP中设计比较巧妙的地方.其通过AbpStartupConfiguration,Castle的依赖注入,Dictionary对象和扩展方法很巧妙的实现了配 ...

最新文章

  1. 2019计算与系统神经科学大会Cosyne 前沿研究汇总
  2. android 拍照不能保存图片格式,Android 拍照后保存到手机里,在相册找不到
  3. spark.mllib:回归算法
  4. 【vue】跟着老马学习vue-数据双向绑定
  5. 开源推荐:.Net Core3.1 + EF Core + LayUI 封装的MVC版后台管理系统
  6. Java学习笔记(基本数据类型和变量命名规则)
  7. 计算机专业应届生年薪30多万,制造焦虑,非广告,请看截图
  8. 基于JAVA+SpringMVC+Mybatis+MYSQL的田径运动会管理系统
  9. .NET组件程序设计0723
  10. mysql巡检常用命令_总结Linux下系统巡检常用命令
  11. while 循环 格式化输出
  12. Flutter高级第3篇:底部 Tab 切换保持页面状态的几种方法
  13. 20. 远程端口查看
  14. Matlab将double类型转换为正整数类型
  15. VS2005下配置OGRE
  16. 面部捕捉技术_FT45面部表情捕捉系统--说明书(中文版)
  17. 你在工作中遇到了哪些问题,解决办法是什么
  18. 工作日志之Sonar扫描错误处理-Sonar扫描结果入库 java.sql.BatchUpdateException: Incorrect string value: '\xF3\xA3\xAC\xB
  19. Win32窗口程序实例
  20. java 24字母_java 时间格式化中的模式字母

热门文章

  1. 写了个简单的pdo的封装类
  2. java 读取使用keytool生产的keystore文件
  3. 代理网络中安装tomcat的注意事项
  4. 在远程桌面连接中使用命令行参数
  5. VS2008无法识别的版本3.5
  6. 保持 Go 模块兼容
  7. Linux 命令(95)—— test 命令
  8. 2.maven 安装配置
  9. Oracle数据库创建表空间
  10. 面向云的.net core开发框架