从零开始构建一个Reactor模式的网络库(二)线程类Thread
线程类Thread是对POSIX线程的封装类,因为要构建的是一个Linux环境下的多线程网络库,对线程的封装是很必要的。
首先是CurrentThread命名空间,主要是获取以及缓存线程id:
#ifndef CURRENTTHREAD_H
#define CURRENTTHREAD_H
#include <unistd.h>
#include <sys/syscall.h> namespace CurrentThread
{
extern __thread int t_cachedTid;
inline void cacheTid()
{
t_cachedTid=static_cast<int>(::syscall(SYS_gettid));
}
inline int tid()
{
if(t_cachedTid==)
cacheTid();
return t_cachedTid;
}
} #endif // CURRENTTHREAD_H
这里要注意一个问题,就是线程id的获取。
线程id的获取可以通过几种方式,最方便的是syscall(),是一个glibc库函数而不是一个系统调用,此时返回的是内核中的线程id。
因为Linux的线程实现中,线程事实上也是一个进程,因此返回的tid事实上就是pid,pid_t在Linux中一般实现为int。
另外,POSIX线程库提供了函数pthread_self(),但是该函数返回的是进程中的线程id,类型为pthread_t,一般是unsigned long类型,并不是内核中的实际id,在调试和排查错误时并不方便。
#ifndef THREAD_H
#define THREAD_H
#include <pthread.h>
#include <memory>
#include <functional>
#include "Types.h"
#include <atomic>
#include "Mutex.h" namespace mini
{
class Thread
{
public:
typedef std::function<void()> ThreadFunc;
explicit Thread(const ThreadFunc& func,const string& ThreadName=string());
~Thread(); int join();
void start();
pid_t tid() const { return *tid_; }
bool started() const { return started_; }
const string& name() const {return name_;}
private: void setDefaultName(); bool started_; //if the thread started
bool joined_; //if joined settled
pthread_t pthreadId_; //thread id in the process
std::shared_ptr<pid_t> tid_; //shared_ptr to the tid
string name_; //name of the thread
ThreadFunc func_; //function for the thread
static std::atomic<int> numsCreated_; //record nums of created threads
}; } #endif // THREAD_H
Thread.h头文件中定义了Thread类,成员包括启动状态、tid和pthreadid、实际执行的函数以及名字等。
#include "CurrentThread.h"
#include "Thread.h"
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h> namespace CurrentThread
{
__thread int t_cachedTid=;
/*
bool isMainThread()
{
return ::getpid()==tid();
}
*/
}
namespace mini
{
struct ThreadData
{
typedef mini::Thread::ThreadFunc ThreadFunc;
ThreadFunc func_;
mini::string name_;
std::weak_ptr<pid_t> wkTid_;
ThreadData(const ThreadFunc& func,const string& name,const std::shared_ptr<pid_t>& tid)
:func_(func),name_(name),wkTid_(tid)
{}
void runInThread()
{
pid_t tid=CurrentThread::tid();
std::shared_ptr<pid_t> ptid=wkTid_.lock();
if(ptid)
{
*ptid=tid;
ptid.reset();
}
func_();
} };
std::atomic<int> Thread::numsCreated_(); void Thread::setDefaultName()
{
int num=numsCreated_++;
if(name_.empty())
{
char buf[];
snprintf(buf,sizeof buf,"Thread%d", num);
name_=buf;
}
} void* startThread(void* obj)
{
ThreadData* data=static_cast<ThreadData*>(obj);
data->runInThread();
delete data;
return NULL;
} Thread::Thread(const ThreadFunc &func, const string &ThreadName)
:started_(false),
joined_(false),
pthreadId_(),
tid_(new pid_t()),
func_(func),
name_(ThreadName)
{
setDefaultName();
} void Thread::start()
{
started_=true;
ThreadData* data=new ThreadData(func_,name_,tid_);
if(pthread_create(&pthreadId_,NULL,&startThread,data));
{
started_=false;
//delete data;
//LOG_SYSFATAL<<"FAILED in pthread_create";
}
} int Thread::join()
{
joined_=true;
return pthread_join(pthreadId_,NULL);
} Thread::~Thread()
{
if(started_&&!joined_)
pthread_detach(pthreadId_);
}
}
由于向pthread_create中传递要执行的线程函数以及参数比较复杂,定义了一个内部类ThreadData。
ThreadData中有一个weak_ptr<pid_t>,当线程实际被创建并开始运行时,创建一个临时的shared_ptr,确保Thread以及ThreadData被正确创建。
事实上,Thread类对象创建时,线程并没有实际开始运行,直到调用start()才开始执行。
执行线程可以调用join()来等待Thread线程的结束。默认情况下,线程资源会保留直到调用pthread_join()。
析构函数简单地调用pthread_detach()来设置线程分离,从而在线程函数执行结束后直接退出,线程资源也会在线程终止时立即被回收。
从零开始构建一个Reactor模式的网络库(二)线程类Thread的更多相关文章
- 从零开始构建一个Reactor模式的网络库(一) 线程同步Mutex和Condition
最近在学习陈硕大神的muduo库,感觉写的很专业,以及有一些比较“高级”的技巧和设计方式,自己写会比较困难. 于是打算自己写一个简化版本的Reactor模式网络库,就取名叫mini吧,同样只基于Lin ...
- 从零开始构建一个的asp.net Core 项目
最近突发奇想,想从零开始构建一个Core的MVC项目,于是开始了构建过程. 首先我们添加一个空的CORE下的MVC项目,创建完成之后我们运行一下(Ctrl +F5).我们会在页面上看到"He ...
- 从零开始构建一个centos+jdk7+tomcat7的docker镜像文件
从零开始构建一个centos+jdk7+tomcat7的镜像文件 centos7系统下docker运行环境的搭建 准备centos基础镜像 docker pull centos 或者直接下载我准备好的 ...
- 从零开始构建一个的asp.net Core 项目(一)
最近突发奇想,想从零开始构建一个Core的MVC项目,于是开始了构建过程. 首先我们添加一个空的CORE下的MVC项目,创建完成之后我们运行一下(Ctrl +F5).我们会在页面上看到“Hello W ...
- 2021 从零开始打造一个自己的 UI 组件库
2021 从零开始打造一个自己的 UI 组件库 refs GUI https://github.com/xgqfrms/gui/ https://www.npmjs.com/package/@xgqf ...
- [计算机视觉]从零开始构建一个微软how-old.net服务/面部属性识别
大概两三年前微软发布了一个基于Cognitive Service API的how-old.net网站,用户可以上传一张包含人脸的照片,后台通过调用深度学习算法可以预测照片中的人脸.年龄以及性别,然后将 ...
- 从零开始构建一个的asp.net Core 项目(二)
接着上一篇博客继续进行.上一篇博客只是显示了简单的MVC视图页,这篇博客接着进行,连接上数据库,进行简单的CRUD. 首先我在Controllers文件夹点击右键,添加->控制器 弹出的对话框中 ...
- .Net 从零开始构建一个框架之基本实体结构与基本仓储构建
本系列文章将介绍如何在.Net框架下,从零开始搭建一个完成CRUD的Framework,该Framework将具备以下功能,基本实体结构(基于DDD).基本仓储结构.模块加载系统.工作单元.事件总线( ...
- 构建一个基于事件分发驱动的EventLoop线程模型
在之前的文章中我们详细介绍过Netty中的NioEventLoop,NioEventLoop从本质上讲是一个事件循环执行器,每个NioEventLoop都会绑定一个对应的线程通过一个for(;;)循环 ...
随机推荐
- 微信小程序,不同的输入框显示
<!--pages/index/Component/TextInput/TextInput.wxml--> <view class="viewTitle"> ...
- openfalcon的安装和使用
蛮复杂的样子 根据官方文档指导,一步一步走起:https://book.open-falcon.org/zh_0_2/quick_install/prepare.html 单机安装的过程:单击安装会把 ...
- WCF 内存入口检查失败 Memory gates checking failed
在做JC系统时,出现这样的错误: 出现该错误信息的原因是因为WCF服务激活之前,系统应该具有的最小内存量不足config文件中设置的百分比.我是在本机调试的时候出现的. 解决方法: 关闭 ...
- [转载]JSONP跨域的原理解析
JavaScript是一种在Web开发中经常使用的前端动态脚本技术.在JavaScript中,有一个很重要的安全性限制,被称为“Same-Origin Policy”(同源策略).这一策略对于Java ...
- java中类加载顺序(深入Java)
未涉及虚拟机 0.<init>与<clinit>的区别 1.类的加载过程 2.类的使用方式 3.类的加载来源 4.重载之泛型参数不同可以吗 5.参考 引子 记得上次中秋一哥们写 ...
- (转)C中的volatile用法
volatile 影响编译器编译的结果,指出,volatile 变量是随时可能发生变化的,与volatile变量有关的运算,不要进行编译优化,以免出错,(VC++ 在产生release版可执行码时会进 ...
- Java基础 面向对象的详解
1.1 万物皆对象 我们是怎么认识世界的? 人类从小就不断的接触到各种各类存在世界上的各种生物,然后通过事物的公共特性,将它们归类,所以以后就不会出现见到猫叫老虎.那么我们在现实生活中,是通过具体的某 ...
- ++*p,(*p)++,*p++与*++p四者的区别
四者的区别(*和++优先级相同默认从右向左运算) ++*p相当于++(*p),表示先给p指向的变量值加1,然后取该变量的值. (*p)++相当于先取p指向的变量,然后该变量值加1. *p++相当于*( ...
- 在VS2010中使用MySQL-转载
下面这篇文章进过测试,确实可以.记下来,留作记录. http://blog.sina.com.cn/s/blog_782496390100qjcu.html
- mysql----其他小技巧
小技巧: min/max优化 在表中,一般都是经过优化的. 如下地区表 id area pid 1 中国 0 2 北京 1 ... 3115 3113 我们查min(id), id是主键,查Min(i ...