【C/C++开发】C++实现简单的线程类
C++封装一个简单的线程类
多线程编程简介:
大家在编程时,经常需要在程序中启动一个或多个线程来处理任务,而如果每次都是去调用系统创建线程的API函数来创建,代码量虽不多,但线程的创建和业务逻辑代码就揉在一起了,且创建多个线程的时候,有大量的重复代码,不便于维护。若我们把创建线程和销毁线程的这些共同的代码封装到一个类中,这样我们可以更专注业务逻辑的实现,在其它地方直接拿来用就行,程序也便于维护和扩展。而且这样的话即使程序所使用的线程库更换了,但线程类提供的接口没变,所以我们的业务逻辑代码也不用任何的改动。
创建一个线程也无非就是调用系统线程API或第三方库的API,然后传入线程函数地址和线程运行所需要的参数即可,所以我们需要将此部分代码抽象出来,并提供使用接口即可。
一个线程基类Thread
这里我们使用的是Apache提供的apr库,该库具有跨平台性,当然不管使用什么库,我们提供的接口都是一样的,且线程创建和销毁的逻辑是一样的。代码:
2 {
3 public:
4 Thread(bool bDetach = true);
5 virtual ~Thread();
6
7 virtual void run() = 0; //业务接口
8
9 int start(); //启动线程
10 int join(); //等待线程线束
11 void destroy(); //销毁线程所申请的资源
12
13 // attribute functions
14 int get_thread_id() { return thr_id_; }
15 void set_thread_id(unsigned long thrId) { thr_id_ = thrId; }
16
17 protected:
18 static void* __stdcall thread_proc(apr_thread_t* th, void* data);
19 void notify() { cond_.signal(); }
20 bool check_interrupt() { return bExit_; }
21
22 private:
23 size_t thr_id_; //线程ID
24 bool bExit_; //线程是否要退出标志
25
26 apr_thread_t* thr_; //线程句柄
27 Condition cond_; //线程函数中等待任务的条件变量
28
29 private:
30 //not implement
31 Thread(const Thread& );
32 Thread& operator=(const Thread& );
33 };
一些说明:
- 我们在start()方法中调用apr库提供的线程API创建一个线程: apr_thread_create(),并将线程函数thread_proc()和Thread*为线程函数参数传入apr_thread_create()即可,具体代码在后面贴出。
- Join()函数用于等待线束线程,而destroy() 则是用于显示销毁该线程所占用的资源。
- 线程基类有一个纯虚函数run(),即应用线程继承Thread类后必须实现run()函数,即实现程序的业务逻辑
- 在start()创建完线程后系统便在某一时刻开始执行thread_proc()方法,我们在该方法中会调用run()函数,由于多态性,也就会调用应用程序多实现的run()函数了
具体实现(Thread.cpp):
2 {
3 apr_status_t rv;
4 apr_threadattr_t* thrattr = NULL;
5 apr_threadattr_create(&thrattr, g_mpool);
6
7 //创建一个线程
8 if ((rv = apr_thread_create(&thr_, thrattr, Thread::thread_proc, this, g_mpool)) != APR_SUCCESS)
9 {
10 set_error_code(rv);
11 char errbuf[512];
12 apr_strerror(rv, errbuf, sizeof(errbuf));
13 log2DebugView("Thread: failed create a thread: [%d][%s]\n", rv, errbuf);
14 return rv;
15 }
16 apr_sleep(100000); //ensure the thead_proc is running
17
18 return rv;
19 }
20 //等待线束线程
21 int Thread::join()
22 {
23 bExit_ = true;
24 notify();
25 apr_sleep(100000);
26
27 apr_status_t rv = 0;
28 return apr_thread_join(&rv, thr_);
29 }
30 //销毁线程
31 void Thread::destroy()
32 {
33 if (!bExit_)
34 join();
35 cond_.destroy();
36 }
37 //线程函数,将会调用子类实现的run()方法
38 void* Thread::thread_proc(apr_thread_t* th, void* data)
39 {
40 Thread* pthis = static_cast<Thread*>(data);
41 while (!pthis->bExit_)
42 {
43 //调用子类实现的run()方法
44 pthis->run();
45
46 //wait for signal
47 pthis->cond_.wait();
48 }
49
50 printf("thread exit, id: %d\n", pthis->get_thread_id());
51 apr_thread_exit(th, APR_SUCCESS);
52 return NULL;
53 }
这里我们不要太过意研究线程在具体代码是如何创建的,比如在start()函数中,在windows下线程函数可以是 UINT thread_proc(LPVOID param); 而创建线程则是调用__beginthreadex()的windows API即可,具体可参照windows的线程创建和销毁逻辑。线程使用如下:
应用示例
2 class MyThread : public Thread
3 {
4 public:
5 MyThread(){ loop_ = true; }
6 virtual MyThread(){}
7
8 //只关心如何实现业务逻辑,而看不到线程是如何创建的
9 virtual void run()
10 {
11 while (loop)
12 {
13 //do some work
14 }
15 printf("MyThread exit.\n");
16 }
17
18 private:
19 bool loop_;
20 };
21
22 // 在程序中使用如下
23 MyThread* pmt = new MyThread();
24 pmt->start(); //调用start()方法后,即启动了一个线程了
这样,我们就完成了一个线程类的封装和使用了,代码不多,但很常用哈。最后说明一下线程类中使用一个Condition的类,其实也就是一个对事件的封装使用,完全可以用windows下的 SetEvent()/WaitForSingleObject()替代或Linux下的pthread_condition_t的pthrad_condition_signal()/pthread_condition_wait()替代,即等待事件和通知事件的处理。
下一节我将会利用这个线程类实现一个简单的线程池,便于我们在程序中使用。
【C/C++开发】C++实现简单的线程类的更多相关文章
- Delphi线程类 DIY(把类指针作为参数传进去,就可以执行类里面的方法啦)
Delphi 封装了一个很强大的线程类 TThread, 我们也自己动手制作一个简单的线程类 首先Type一个类 type TwwThread = class constructor Create; ...
- 【C/C++开发】C++实现简单的线程池
C++实现简单的线程池 线程池编程简介: 在我们的服务端的程序中运用了大量关于池的概念,线程池.连接池.内存池.对象池等等.使用池的概念后可以高效利用服务器端的资源,比如没有大量的线程在系统中进行上下 ...
- iOS开发网络篇—简单介绍ASI框架的使用
iOS开发网络篇—简单介绍ASI框架的使用 说明:本文主要介绍网络编程中常用框架ASI的简单使用. 一.ASI简单介绍 ASI:全称是ASIHTTPRequest,外号“HTTP终结者”,功能十分强大 ...
- 封装一个简单好用的打印Log的工具类And快速开发系列 10个常用工具类
快速开发系列 10个常用工具类 http://blog.csdn.net/lmj623565791/article/details/38965311 ------------------------- ...
- java开发两年,这些线程知识你都不知道,你怎么涨薪?
前言 什么是线程:程序中负责执行的哪个东东就叫做线程(执行路线,进程内部的执行序列),或者说是进程的子任务. Java中实现多线程有几种方法 继承Thread类: 实现Runnable接口: 实现Ca ...
- iOS开发UI篇—简单的浏览器查看程序
iOS开发UI篇—简单的浏览器查看程序 一.程序实现要求 1.要求 2. 界面分析 (1) 需要读取或修改属性的控件需要设置属性 序号标签 图片 图片描述 左边按钮 右边按钮 (2) 需要监听响应事件 ...
- iOS开发UI篇—简单介绍静态单元格的使用
iOS开发UI篇—简单介绍静态单元格的使用 一.实现效果与说明 说明:观察上面的展示效果,可以发现整个界面是由一个tableview来展示的,上面的数据都是固定的,且几乎不会改变. 要完成上面的效果, ...
- iOS开发Swift篇—简单介绍
iOS开发Swift篇—简单介绍 一.简介 Swift是苹果于2014年WWDC(苹果开发者大会)发布的全新编程语言 Swift在天朝译为“雨燕”,是它的LOGO 是一只燕子,跟Objective-C ...
- 李洪强iOS开发之- 实现简单的弹窗
李洪强iOS开发之- 实现简单的弹窗 实现的效果: 112222222222223333333333333333
随机推荐
- 关于 $.proxy(fn,context,arg) 方法
<!-- $.proxy(fn,this,agrument); proxy 代理 思考做酒的代理商argument就是代理商 把fn所在的作用域对象的参数/属性 代理给fn执行. fn: 要被调 ...
- HTML 008 head
HTML <head> 查看在线实例 <title> - 定义了HTML文档的标题使用 <title> 标签定义HTML文档的标题 <base> - 定 ...
- php类的定义与实例化方法
php类的定义 类是对某个对象的定义.它包含有关对象动作方式的信息,包括它的名称.方法.属性和事件.实际上它本身并不是对象,因为它不存在于内存中.当引用类的代码运行时,类的一个新的实例,即对象,就在内 ...
- php数据类型之查看和判断数据类型
我们知道了一个数据的类型,才能进行下一步操作.后面的时候,大家可以学习到更多的知识——自定义功能(函数). 我们来做一个场景模拟:(注:眼前不用会写这个函数,以后会教大家) 假设,我们可以写一个智能的 ...
- 学到了林海峰,武沛齐讲的Day23-完
10月11号生了儿子,很高心..不好的是孩子住院了,14号出院,晚上外公去世了,15号赶回老家.....20号回贵阳,21号回公司办事....我要坚定的学习下去...以前几乎是卡在这里就学不下去了.加 ...
- ES 的基本用法
ES的基本用法 ES的基本概念 1> 集群和节点 一个es集群是由一个或多和es节点组成的集合 每一个集群都有一个名字, 如之前的wali 每个节点都有自己的名字, 如之前的master, sl ...
- umediter实现粘贴word图片
图片的复制无非有两种方法,一种是图片直接上传到服务器,另外一种转换成二进制流的base64码目前限chrome浏览器使用首先以um-editor的二进制流保存为例:打开umeditor.js,找到UM ...
- FCFS,SJF,HRN
1.编写并调试一个单道处理系统的作业等待模拟程序. 作业等待算法:分别采用先来先服务(FCFS),最短作业优先(SJF).响应比高者优先(HRN)的调度算法. 对每种调度算法都要求打印每个作业开始运行 ...
- P1069 细胞分裂——数学题,质因数分解
P1069 细胞分裂 我们求的就是(x^k)|(m1^m2) k的最小值: 先给m1分解质因数,再给每个细胞分解: 如果m1有的质因数,细胞没有就跳过: 否则就记录答案: 注意整数除法下取整的原则: ...
- python ros 订阅imu数据,实时显示欧拉角
#!/usr/bin/env python # -*- coding: utf- -*- import rospy import math from sensor_msgs.msg import Im ...