13muduo_base库源码分析(四)
来源:互联网 发布:81端口活跃ip段 编辑:程序博客网 时间:2024/06/03 19:51
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{ // internal extern __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;}
阅读全文
1 0
- 13muduo_base库源码分析(四)
- 11muduo_base库源码分析(二)
- 12muduo_base库源码分析(三)
- 15muduo_base库源码分析(六)
- 16muduo_base库源码分析(七)
- 17muduo_base库源码分析(八)
- 18muduo_base库源码分析(九)
- 19muduo_base库源码分析(十)
- 20muduo_base库源码分析(十一)
- muduo_base 源码分析:Timestamp
- muduo_base 源码分析:AtomicIntegerT
- 高并发服务器架构笔记(3)——muduo_base 源码分析
- 高并发服务器架构笔记(3)——muduo_base 源码分析
- 28muduo_net库源码分析(四)
- Logcat源码分析(四)
- pomelo源码分析(四)
- H264源码分析(四)
- mosquitto源码分析(四)
- 22、栈的压入、弹出序列
- 深度学习笔记---ReL解决梯度消失
- Catch That Cow
- ?NullPointerException
- Linux进程端口,防火墙端口管理
- 13muduo_base库源码分析(四)
- JSP之自定义标签的执行过程
- CSS基础试题
- POJ 3281 Dining(最大流)
- 二分查找
- 使用Afl-fuzz (American Fuzzy Lop) 进行fuzzing测试(二)——详细使用说明(README.txt)
- TabLayout使用详解
- Python 函数
- jQuery ajax