20200131_用C++封装POSIX线程

安稳与你 提交于 2020-02-02 03:58:38

1. 想法

通过一个对象来调用,这种方法可以看成是主线程调用一个对象,相当于只有一个主线程,没有子线程。而我们的本意是产生子线程,因此这种方法是不对的。

解决方法:把run函数设置成私有的。

 //
 /// @file    Thread.h
 /// @author  xiekun(519686353@qq.com)
 /// @date    2020-01-31 17:53:03
 //
#include <iostream>
using std::cout;
using std::endl;
class MyThread
{
	public:
		void run()
		{
			//...
		}
};
int main(void)
{
	MyThread mythread;
	mythread.run();     //这种写法是error的
	return 0;
}

2. 一些要注意的地方

  • pthread_creat()函数 创建线程

    • 第一个是 线程 id
    • 第二个是 线程属性 一般写NULL
    • 第三个是 这个线程要运行的程序
    • 第四个是 一般写NULL 或者写 传给第三个的(void *)参数(详见后面代码)
  • include <stdlib.h> 随机数函数的头文件

    • srand() 生成一个种子
    • srand(clock()) 获取每一刻的时间
  • include <unistd.h>

    • sleep(1) 睡1秒
  • 使用工程文件makefile

    • 有多个.cc文件需要一起编译,也可以使用(g++ *.cc -lpthread)同时编译.cc文件

3. 代码文件

其实不使用命名空间wd也可以 大家可以自行去实现

Thread.h 头文件

///
/// @file    Thread.h
/// @author  xiekun(519686353@qq.com)
/// @date    2020-01-31 17:53:03
///

#ifndef __THREAD_H__
#define __THREAD_H__


#include "Noncopyable.h"

#include <pthread.h>

#include <iostream>

namespace wd {

class Thread
	: Noncopyable  //这种写法是私有继承 不需要noncopyable的接口 他也没提供接口 所以私有
/*
 * 派生类在赋值复制操作时,
 * 如果自己没有定义相关操作的函数
 * 则会调用父类的赋值复制操作函数
 * 这样 使得该派生类无法进行赋值赋值操作
 *
 * Thread就变成了 具有对象语义的类 --> 不能被复制
 */
{

  public:
	Thread();
	virtual ~Thread();	//有了虚函数run 析构函数就要设置成虚构的

	void start();	//开启子进程
	void join();	//回收子进程

	bool isRunning() const { return _isRunning; }
  private:
	virtual void run() = 0;	//(虚函数一般作为接口)这是线程要执行的任务
	/*
	 * 这里要设置成static没有this指针
	 * thread.cc中调用thread_create的第三个参数需要的是void * 格式
	 * 如果不使用static 则返回值带有this指针
	 * 所以 需要改成静态函数
	 *
	 */

	static void * threadFunc(void *);
  private:
	pthread_t _pthid;
	bool _isRunning;
};

}
#endif




Thread.cc 实现Thread.h头文件

///
/// @file    Thread.cc
/// @author  xiekun(519686353@qq.com)
/// @date    2020-01-31 18:12:05
///
#include "Thread.h"

namespace wd {
Thread::Thread()
	: _pthid(0)
	, _isRunning(false) {

}
Thread::~Thread() {
	if (_isRunning) {
		pthread_detach(_pthid);
		_isRunning = false;
	}
}


void Thread::start() {
	/*
	 * 创建线程 第四个参数this传给threadFunc
	 * 作为threadFunc(void *)的参数 这个参数是void *类型的
	 *
	 */
	pthread_create(&_pthid, NULL, threadFunc, this);
	_isRunning = true;
}
void Thread::join() {
	if (_isRunning) {
		pthread_join(_pthid, NULL);
		_isRunning = false;
	}
}

void * Thread::threadFunc(void * arg) {
	/*需要把(void *)强转成(Thread*) */
	Thread * p = static_cast<Thread *>(arg);
	if (p)
		p->run();	//虚函数的使用需要调用对象(表现多态虚函数机制 )
	return NULL;
}
}

TestThread.cc 测试主程序

///
/// @file    TestThread.cc
/// @author  xiekun(519686353@qq.com)
/// @date    2020-01-31 21:42:22
///
#include "Thread.h"

#include <stdlib.h>

#include <iostream>
#include <memory>
using std::cout;
using std::endl;
using std::unique_ptr;
class MyThread
	: public wd::Thread { //bug1 wd::
  public:
	~MyThread() { cout << "~MyThread" << endl; }
  private:
	void run() override {
		int cnt = 10;
		srand(clock());
		while (cnt--) {
			int number = rand() % 100;
			cout << "sub thread " << pthread_self()
			     << ":getNumber = " << number << endl;
		}
	}
};

void test0() {
	cout << "main thread " << pthread_self() << endl;
	unique_ptr<wd::Thread> mythread(new MyThread());
	mythread->start();
	mythread->join();
}
void test1() {
	cout << "11main thread " << pthread_self() << endl;
	MyThread mythread;
	mythread.start();
	mythread.join();

//	MyThread mythread2(mythread);
	/*
	 * 这是一个复制操作 需要被禁止error
	 * 以前的解决办法是:
	 * 方法1.把赋值操作运算符放在private里面
	 * 方法2.=delete 赋值操作
	 * 本例中的方法:
	 * 写一个noncopyable类,mythread继承该类,详见Thread.h
	 *
	 * 派生类在赋值复制操作时,
	 * 如果自己没有定义相关操作的函数
	 * 则会调用父类的赋值复制操作函数
	 * 这样 使得该派生类无法进行赋值赋值操作
	 *
	 */
}

int main () {
	test1();
	return 0;
}

Noncopyable.h 禁止赋值/复制操作

Thread.h继承

///
/// @file    Noncopyable.h
/// @author  xiekun(519686353@qq.com)
/// @date    2020-01-31 23:03:26
///

#ifndef __NONCOPYABLE_H__
#define __NONCOPYABLE_H__

namespace wd {
class Noncopyable {
	/*
	 * 这个类不用生成对象
	 * 用抽象类的第二种形式:
	 * protected就可以了
	 */
  protected:
	Noncopyable() {};
	~Noncopyable() {};
	Noncopyable(const Noncopyable &) = delete;
	Noncopyable & operator=(const Noncopyable &) = delete;
};
}
#endif

makefile 工程文件

也可以不使用makefile:
有多个.cc文件需要一起编译,则可以使用(g++ *.cc -lpthread)同时编译.cc文件

INC_DIR:= ./
SRC_DIR:= ./
SRCS:= $(wildcard $(SRC_DIR)*.cc)  
CC:= g++
CXXFLAGS:= -g -Wall $(addprefix -I, $(INC_DIR))
LIBS:= -lpthread
OBJS:= $(patsubst %.cc, %.o, $(SRCS))

BIN_EXE:= TestThread.exe

$(BIN_EXE):$(OBJS)
	$(CC) -o $@ $^ $(CXXFLAGS)  $(LIBS)  

%.o:%.cc
	$(CC) -o $@  -c $< $(CXXFLAGS)  $(LIBS)  

print:
	@echo $(OBJS)
clean:
	rm -rf $(OBJS) $(BIN_EXE) 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!