Bo——使用基于对象的方法封装一个线程库-- function<> & bind

本文探讨了基于对象的编程与面向对象的区别,并介绍了C++标准库中的std::function和std::bind。通过示例展示了如何使用std::bind预绑定参数创建线程,以及如何在Thread类中使用std::function作为回调函数。在TestMain.cpp中,展示了如何使用std::bind与智能指针结合,灵活地在线程中执行任务。
摘要由CSDN通过智能技术生成

Bo——使用基于对象的方法封装一个线程库-- function<> & bind

function<> & bind

很多人没有区分“面向对象”和“基于对象”两个不同的概念。面向对象的三大特点(封装,继承,多态)缺一不可。通常“基于对象”是使用对象,但是无法利用现有的对象模板产生新的对象类型,继而产生新的对象,也就是说“基于对象”没有继承的特点。而“多态”表示为父类类型的子类对象实例,没有了继承的概念也就无从谈论“多态”。现在的很多流行技术都是基于对象的,它们使用一些封装好的对象,调用对象的方法,设置对象的属性。但是它们无法让程序员派生新对象类型。他们只能使用现有对象的方法和属性。所以当你判断一个新的技术是否是面向对象的时候,通常可以使用后两个特性来加以判断。“面向对象”和“基于对象”都实现了“封装”的概念,但是面向对象实现了“继承和多态”,而“基于对象”没有实现这些。----摘自网络

std::fuinction<R(T1,T2,T3…Tn)>

☞这是一个模板实现的函数对象类,它可以包装其它任意的函数对象,而被包装的函数对象具有类型为T1,T2,…,TN的参数,其返回值为R类型

☞function 对象的最大用处在于实现函数回调

std::bind()

☞bind是这样一种机制,它可以预先把指定可调用实体的某些参数绑定到已有的变量,产生一个新的可调用实体

☞绑定的参数的个数不受限制

☞绑定的具体哪些参数也不受限制,由用户指定

☞bind预先绑定的参数需要传具体的变量或值进去,是pass-by-value(值传递)的

☞对于不事先绑定的参数,需要传std::placeholders进去,从_1开始,依次递增

☞bind的返回值是可调用实体,可以直接赋给std::function对象

基于对象 线程库UML类图

在这里插入图片描述

Thread.h

// Created by 60263 on 2020/10/16.
// This is 
#ifndef __THREAD_H_
#define __THREAD_H_
#include "Noncopyable.hpp"
#include <pthread.h>
#include <functional>

namespace wd {
class Thread : public Noncopyable {
 public:
  using ThreadCallback = std::function<void()>;

  Thread(ThreadCallback && cb);//传递bind绑定的函数对象
  ~Thread();

  void start();
  void join();


 private:
  static void* threadFunc(void * arg);//线程函数
  pthread_t _pthid;//线程id
  bool _isRunning;//判断线程是否运行
  ThreadCallback _cb;//function函数对象
};
}
#endif //__THREAD_H_

Thread.cpp

// Authors: Handling
// Created by 60263 on 2020/10/16.
// This is 

#include "Thread.h"
namespace wd {
Thread::Thread(ThreadCallback &&cb) : _pthid(0),
                                      _isRunning(false),
                                      _cb(std::move(cb)) {}
Thread::~Thread() {
  if(_isRunning){
    pthread_detach(_pthid);//如果线程仍在运行则detach交给系统托管
  }
}

void Thread::start() {
  if(pthread_create(&_pthid, nullptr,threadFunc,this)){//threaFunc必须为static如果是成员函数
      //则它默认含有this参数,再传参的时候会报错。
    perror("pthread_create");
    return;
  }
  _isRunning =true;
}

void Thread::join() {
  if(_isRunning){
    pthread_join(_pthid, nullptr);
  }
}

void* Thread::threadFunc(void *arg) {
  Thread *p = static_cast<Thread *>(arg);//传递进来的是this,即thread对象的入口地址
  if(p){
    p->_cb();
  }

  return nullptr;
}
}

TestMain.cpp

#include "Thread.h"
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <memory>

#include <iostream>

using std::cout;
using std::endl;
using std::unique_ptr;

void run(){
  ::srand(::time(nullptr));
  int cnt = 20;
  while (cnt-- >0){
    int number = ::rand()%100;
    cout << "threadid " << pthread_self()
         << ": number = " << number << endl;

    ::sleep(1);
  }
}

class Task
{
 public:
  void process()
  {
    cout << "Task::process()" << endl;
    run();
  }

  void execute(int x, int y)
  {
    cout << "Task::execute(int,int)" << x << "," << y << endl;
  }
};

void test0()
{

  cout << "main thread: " <<  pthread_self() << endl;
  //unique_ptr<wd::Thread> mythread(new wd::Thread(run));

  unique_ptr<Task> ptask(new Task());

  //基于对象的写法会更灵活
  unique_ptr<wd::Thread> mythread(new wd::Thread(
      std::bind(&Task::process, ptask.get())));//ptask.get()代表this指针
      //std::bind(&Task::execute, ptask.get(), 1, 2)));
      //
      //提前绑定参数时, bind采用的是值传递, 会对Task() 临时对象进行复制
      //std::bind(&Task::execute, Task(), 1, 2)));

  mythread->start();
  mythread->join();
}


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

运算结果

在这里插入图片描述

如主程序所示,借用智能指针托管,thread在创建对象的时候参数列表中创建临时对象临时对象又使用bind函数绑定了不同实现的回调函数,十分灵活。

总结一下总体思路:

在Thread类中注册一个 function<void()>的回调函数,这个回调函数会在thread对象创建时通过bind函数绑定。之后手动调用start成员函数,进行了子线程的创建,子线程函数threadFunc中调用回调函数。

bind的参数为可变参数,它可以传递一个task()临时对象也可以通过。ptask.get()获取对象的this指针。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值