C++ 使用基类的成员函数作为线程函数的示例

144 篇文章 6 订阅

 这一阶段要写一个传感器插件管理框架,因此定义了一个基类,并定义了一堆虚函数。然后在子类中实现这些函数。最后测试时,将子类的对象赋给父类的指针,然后使用父类的成员函数作为线程函数,在线程执行中实际调用子类的成员函数。以下是源代码,基于Cmake编译。

完整代码请参考我的资源空间https://download.csdn.net/download/jinking01/12849309,可自行下载

基类文件:include/sensorPluginBase.h

#ifndef _H_SENSOR_PLUGIN_BASE_NAME
#define _H_SENSOR_PLUGIN_BASE_NAME
#include <iostream>
#include <map>
#include <unistd.h>
#include "label.h"
#include <list>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <boost/shared_ptr.hpp>

//#include <thread>
namespace micros_sensor_plugin
{
    using namespace std;

    class SensorPluginBase
    {
    public:
        ///used to control the data generating process. if 0, the plugin should stop to fetch data from the sensor.
        int flag;
        /// reserved for future.
        void *reserved;

    public:
        SensorPluginBase()
        {
            cout << "SensorPluginBase()..." << endl;
        }
        ~SensorPluginBase()
        {
            cout << "~SensorPluginBase()..." << endl;
        }
//注意:所有的虚函数后面都要加{},否则会报错undefined reference to `vtable for micros_sensor_plugin::SensorPluginBase',虽然不是构造函数的问题,但肯定是后面其他几个函数的问题。
        virtual void print() {}
        virtual int init(std::map<std::string, std::string>) {}
//这个是dataProcess调用的函数
        virtual long genData(char *buf) {}
//这个是线程函数,需要2个参数
        virtual void dataProcess(int fd, std::list<boost::shared_ptr<Label>> labelPtrList) {}

        virtual int getFlag() {}

        virtual void setFlag(int aFlag) {}

        virtual void *getReserved() {}

        virtual void setReserved(void *aReserved) {}
    };
} // namespace micros_sensor_plugin
#endif

子类:include/b.h和include/c.h

#ifndef __H_B_H__
#define __H_B_H__
#include "./sensorPluginBase.h"
#include "class_loader/class_loader.h"
#include <time.h>
#include <fstream>
#include <iomanip>
//class_loader/class_loader.h >

#include <random>
namespace micros_sensor_plugin
{
    using namespace std;

    class BSensorPlugin : public SensorPluginBase
    {
        int j;

    public:
       BSensorPlugin();
       ~BSensorPlugin();
        void print()
        {
            cout << "class BSensorPlugin!" << endl;
        }
        int init(const std::map<std::string, std::string> &aMap);

        void dataProcess(int fd, std::list<boost::shared_ptr<Label>> labelPtrList);
        long genData(char *buf);
        int getJ();
        void setJ(int k);
        int getFlag();
        void setFlag(int s);
        void setReserved(void *);
        void *getReserved();
    };
} // namespace micros_sensor_plugin
#endif
#ifndef __H_C_H__
#define __H_C_H__
#include "./sensorPluginBase.h"
#include <random>
#include <time.h>
#include "class_loader/class_loader.h"
#include <fstream>
#include <iomanip>
#include <map>

namespace micros_sensor_plugin
{
    using namespace std;
    class CSensorPlugin : public SensorPluginBase
    {
        int k;

    public:
        CSensorPlugin();
        ~CSensorPlugin();
        void print()
        {
            cout << "class CSensorPlugin!" << endl;
        }
        int init( std::map<std::string, std::string> &aMap);

        void dataProcess(int fd,  std::list<boost::shared_ptr<Label > > labelPtrList);
        long genData(char *buf);
        int getFlag() ;
        void setFlag( int s);
        int getK() ;
        void setK( int k);
        void setReserved( void *) ;
        void *getReserved()  ;
    };
} // namespace micros_sensor_plugin
#endif

子类的实现:src/b.cpp和src/c.cpp

#include "../include/b.h"

namespace micros_sensor_plugin
{
  BSensorPlugin::BSensorPlugin()
  {
    j = 0;
    flag = 0;
    cout<<"BSensorPlugin()..."<<endl;
  }

  BSensorPlugin::~BSensorPlugin()
  {
    j = 0;
    cout<<"~BSensorPlugin()..."<<endl;
  }

  int BSensorPlugin::init(const std::map<std::string, std::string> &aMap)
  {
    return 0;
  }

  long BSensorPlugin::genData(char *buf)
  {
    //char *buf = malloc(1024);
    long length;
    sleep(20);
    length = random() % 255 + 1;
    memset(buf, 0, 1024);
    for (long i = 0; i < length; i++)
    {
      buf[i] = (char)(rand() % 253 + 1);
    }
    return length;
  }

  void BSensorPlugin::dataProcess(int fd, std::list<boost::shared_ptr<Label> > labelPtrList)
  {
    int ret, length;
    char *buf = (char *)malloc(1024);
    int count = 0;
    boost::shared_ptr<Label> labelPtr;
    while (flag)
    {
      sleep(10);
      length = genData(buf); //阻塞式
      //获取标签的内容

      ret = write(fd, buf, length);
      if (ret == length)
      {
        count++;
        cout << "[BSensorPlugin::dataProcess()] The " << count << "-th write " << length << " bytes into file" << endl;
      }
      else
      {
        cout << "[BSensorPlugin::dataProcess()] The " << count << "-th write failed, write " << length << " bytes into file, but should write " << length << " bytes!" << endl;
      }
      if (!labelPtrList.empty())
      {
        for (auto iter = labelPtrList.begin(); iter != labelPtrList.end(); ++iter)
        {
          labelPtr = *iter;
          void *labelContent = labelPtr->getLabelContent();
          ret = write(fd, labelContent, labelPtr->getLabelContentLength());
          if (ret != labelPtr->getLabelContentLength())
            cout << "[BSensorPlugin::dataProcess()] Index write length is not equal to the truth length!" << endl;
        }
      }
    }
  }

  void BSensorPlugin::setJ(int k)
  {
    j = k;
  }

  int BSensorPlugin::getJ()
  {
    return j;
  }

  int BSensorPlugin::getFlag() 
  {
    return flag;
  }

  void BSensorPlugin::setFlag(int aFlag)
  {
    flag = aFlag;
  }

  void *BSensorPlugin::getReserved()
  {
    return reserved;
  }
  void BSensorPlugin::setReserved(void *aReserved)
  {
    reserved = aReserved;
  }

} // namespace micros_sensor_plugin
//对于本示例,我们后面要使用class_loader库将本程序生成.so动态库以供别人使用,所以需要导出函数,建立子类和父类的关系,如果只是验证线程,则后面这句话可以删掉,否则将来找不到依赖包。
CLASS_LOADER_REGISTER_CLASS(micros_sensor_plugin::BSensorPlugin, micros_sensor_plugin::SensorPluginBase)
#include "../include/c.h"
//下面这句话是为了导出函数,是class_loader用到的,目的是生成动态库,以供其他人使用。如果只是测试或者使用线程,则这句话删掉。
CLASS_LOADER_REGISTER_CLASS(micros_sensor_plugin::CSensorPlugin, micros_sensor_plugin::SensorPluginBase)

namespace micros_sensor_plugin
{

  CSensorPlugin::CSensorPlugin()
  {

    flag = 0;
    k = 0;
    cout<<"CSensorPlugin()..."<<endl;
  }

  CSensorPlugin::~CSensorPlugin()
  {
    k = 0;
    cout<<"~CSensorPlugin()..."<<endl;
  }

  int CSensorPlugin::init( std::map<std::string, std::string> &aMap)
  {
    return 0;
  }

  long CSensorPlugin::genData(char *buf)
  {
    //char *buf = malloc(1024);
    long length;
    sleep(15);
    length = random() % 255 + 1;
    memset(buf, 0, 1024);
    for (long i = 0; i < length; i++)
    {
      buf[i] = (char)(rand() % 253 + 1);
    }
    return length;
  }

  void CSensorPlugin::dataProcess(int fd, std::list<boost::shared_ptr<Label> > labelPtrList)
  {
    int ret, length;
    char *buf = (char *)malloc(1024);
    int count = 0;
    boost::shared_ptr<Label> labelPtr;
    while (flag)
    {
      sleep(10);
      length = genData(buf); //阻塞式
      //获取标签的内容

      ret = write(fd, buf, length);
      if (ret == length)
      {
        count++;
        cout << "[CSensorPlugin::dataProcess()] The " << count << "-th write " << length << " bytes into file" << endl;
      }
      else
      {
        cout << "[CSensorPlugin::dataProcess()] The " << count << "-th write failed, write " << length << " bytes into file, but should write " << length << " bytes!" << endl;
      }
      if (!labelPtrList.empty())
      {
        for (auto iter = labelPtrList.begin(); iter != labelPtrList.end(); ++iter)
        {
          labelPtr = *iter;
          void *labelContent = labelPtr->getLabelContent();
          ret = write(fd, labelContent, labelPtr->getLabelContentLength());
          if (ret != labelPtr->getLabelContentLength())
            cout << "[CSensorPlugin::dataProcess()] Index write length is not equal to the truth length!" << endl;
        }
      }
    }
  }


  void CSensorPlugin::setK( int j)
  {
    k = j;
  }

  int CSensorPlugin::getK() 
  {
    return k;
  }

  int CSensorPlugin::getFlag() 
  {
    return flag;
  }

  void CSensorPlugin::setFlag( int aFlag)
  {
    flag = aFlag;
  }

  void *CSensorPlugin::getReserved() 
  {
    return reserved;
  }
  void CSensorPlugin::setReserved( void *aReserved)
  {
    reserved = aReserved;
  }
} // namespace micros_sensor_plugin

依赖的类:include/label.h及src/label.cpp文件是作为线程函数的参数中的一项用到的。对于其他用户根据自己的参数实际情况决定是否引入其他.h和.cpp文件。

#ifndef _H_LABEL_H
#define _H_LABEL_H

#include <iostream>
#include <new>//used for the std::bad_alloc()
#include <string.h>//used for the memset()
#include "constParam.h"//use the LABEL_CONTENT_MAX_LENGTH param in the constructor

using namespace std;

/**
 * @brief Description of the label plugins. Each label plugin correspond to a Label object. A Label object describes the path to the label generator plugin, and the name, content and size of the data generated by the label generator plugin
 * 
 */
class Label
{
    ///name or the label of the data generated by the label generator plugin
    std::string labelName;
    ///path to the label generator plugin
    std::string labelPluginPath;
    ///size of the data generated by the label generator plugin
    int labelContentLength;
    ///content of the data generated by the label generator plugin
    void * labelContent;

public:
    Label();
    Label(std::string aLabelName, std::string aLabelPluginPath, int aLabelContentLength);
    ~Label();
    
    std::string getLabelName() const;
    void setLabelName(std::string aLabelName);
    
    std::string getLabelPluginPath();
    void setLabelPluginPath(std::string aLabelPluginPath);
    
    int getLabelContentLength() const;
    void setLabelContentLength(int aLabelContentLength);
    
    void * getLabelContent() const;
    void setLabelContent(void * aLabelContent);

    /// if using the default constructor (no params), the labelContent will be null, so this function should be called to alloc memory for it.
    int allocMemForLabelContent();


};
#endif
#include "label.h"

Label::Label()
{
    labelContent = NULL;
    printf("In the no param constructor, labelContent ptr = 0x%0x\n", labelContent);
}

/**
 * @brief Construct a new Labe::Labe object and alloc memory for the labelContent. if memory alloc failed, it throws a std::bad_alloc() exception.
 * 
 * @param aLabelName label name got from the plugin description xml file
 * @param aLabelPluginPath  label plugin path got from the plugin description xml file
 * @param aLabelContentLength label content length defined in the plugin description xml file
 */
Label::Label(std::string aLabelName, std::string aLabelPluginPath, int aLabelContentLength)
{
    printf("at begining of the constructor, labelContent ptr = 0x%0x\n", labelContent);
    labelName = aLabelName;
    labelPluginPath = aLabelPluginPath;
    labelContentLength = aLabelContentLength;
    if (labelContentLength < 1)
    {
#if (_DEBUG)
        {
            cerr << "labelContentLength should be positive number!\n";
        }
#endif
        labelName = "";
        labelPluginPath = "";
        labelContentLength = 0;
        labelContent = NULL;
#if (_DEBUG)
        {
            printf("negative labelContentLength, and the labelContent ptr =  0x%0x\n", labelContent);
        }
#endif
        throw std::bad_alloc();
    }
    else if (labelContentLength > LABEL_CONTENT_MAX_LENGTH)
    {
#if (_DEBUG)
        {
            cerr << "labelContentLength too large, its upper limits is " << LABEL_CONTENT_MAX_LENGTH << "!\n";
        }
#endif
        labelName = "";
        labelPluginPath = "";
        labelContentLength = 0;
        labelContent = NULL;
#if (_DEBUG)
        {
            printf("too large labelContentLength, and the labelContent ptr = 0x%0x\n", labelContent);
        }
#endif
        throw std::bad_alloc();
    }
    else
    {
        labelContent = malloc(labelContentLength);
        memset(labelContent, 0, labelContentLength);
#if (_DEBUG)
        {
            printf("Reasonable labelContentLength, and the labelContent ptr = 0x%0x\n", labelContent);
        }
#endif
    }
}

/**
 * @brief Destroy the Label::Label: object
 * 
 */
Label::~Label()
{
    labelName.clear();
    labelPluginPath.clear();
    labelContentLength = 0;
    if (labelContent)
    {
        free(labelContent);
    }
#if (_DEBUG)
    {
        cout << "Label object destroied!" << endl;
    }
#endif
}

/**
 * @brief  return the labelName member of the correspoding LabelPlugin object
 * 
 * @return std::string the labelName 
 */
std::string Label::getLabelName() const
{
    return labelName;
}

/**
 * @brief Set the labelName member of the correspoding LabelPlugin object
 * 
 * @param aLabelName name (description) of label content generated from the label generator plugin
 */
void Label::setLabelName(std::string aLabelName)
{
    labelName = aLabelName;
}

/**
 * @brief Get the labelPluginPath member of the correspoding LabelPlugin object
 * 
 * @return std::string path to the label generator plugin file (.so format)
 */
std::string Label::getLabelPluginPath()
{
    return labelPluginPath;
}

/**
 * @brief Set the labelPluginPath member of the correspoding LabelPlugin object
 * 
 * @param labelPluginPath path to the label generator plugin file (.so format)
 */
void Label::setLabelPluginPath(std::string labelPluginPath)
{
    labelPluginPath = labelPluginPath;
}

/**
 * @brief Get the labelContentLength member of the correspoding LabelPlugin object
 * 
 * @return int the length of the label content generated by the label plugin
 */
int Label::getLabelContentLength() const
{
    return labelContentLength;
}

/**
 * @brief Set the labelContentLength member of the correspoding LabelPlugin object
 * 
 * @param labelContentLength length of the label content
 */
void Label::setLabelContentLength(int labelContentLength)
{
    labelContentLength = labelContentLength;
}

/**
 * @brief Get the labelContent member of the correspoding LabelPlugin object
 * 
 * @return void* the content generated by the label generator plugin 
 */
void *Label::getLabelContent() const
{
    if (labelContent)
    {
        return labelContent;
    }
    else
    {
        cout << "labelContent = NULL\n"
             << endl;
        return 0;
    }
}

/**
 * @brief Set the labelContent member of the correspoding Label:: object
 * 
 * @param aLabelContent the content of the label
 */
void Label::setLabelContent(void *aLabelContent)
{
    labelContent = aLabelContent;
}

/**
 * @brief when using the default constructor @Label::Label() (no params), the labelContent will be null, so this function should be called to alloc memory for it.
 * 
 * @return int the result of allocing memory. 0 : success; 1 : labelContent is not null before calling this function; -1: failed 
 */
int Label::allocMemForLabelContent()
{
    if (labelContent == NULL)
    {
        try
        {
            labelContent = malloc(labelContentLength);
        }
        catch (bad_alloc &ex)
        {
#if (_DEBUG)
            {
                cerr << "[Label::allocMemoryForLabalContent()] Alloc memeory for label content failed!" << endl;
            }
#endif
            return -1;
        }

        return 0;
    }
    return 1;
}

控制_DEBUG变量的一个头文件include/constParams.h

#ifndef _H_CONST_PARAM_H
#define _H_CONST_PARAM_H

#ifndef LABEL_CONTENT_MAX_LENGTH
#define LABEL_CONTENT_MAX_LENGTH 1*1024*1024
#endif

#ifndef SENSOR_CONTENT_MAX_LENGTH
#define SENSOR_CONTENT_MAX_LENGTH 10*1024*1024
#endif

#define _DEBUG 1


#endif

测试函数:test/main.cpp

#include "../include/b.h"
#include "../include/c.h"
#include "../include/sensorPluginBase.h"
#include <thread>
using namespace std;
using namespace micros_sensor_plugin;
int main()
{
   SensorPluginBase *t1, *t2;//父类指针
   t1 = new BSensorPlugin();//子类对象指向父类指针
    //创建线程函数的参数
   std::list<boost::shared_ptr<Label > > aa;
   boost::shared_ptr<Label> labelPtr(new Label());
  // aa.push_back(labelPtr);

   t1->print();
    //线程函数的参数
   int fd1 = open("../B.txt", O_CREAT | O_APPEND | O_RDWR, 0644);
   t1->setFlag(1);
//创建线程,如果使用父类的成员函数地址,则后面紧跟着要把具体实例化对象的指针传过去,后面2个是线程函数的参数。如果使用子类的成员函数地址,则第2个参数t1就不需要了。
   std::thread th1(&SensorPluginBase::dataProcess, t1, fd1,aa);
//脱离主线程,使th1可以独立运行。
   if (th1.joinable())
   {
      th1.detach();
   }
   //t->startThread();

   cout << "SIZEOF BSensorPlugin:" << sizeof(t1) << endl;

    t2 = new CSensorPlugin();
    t2->print();
   t2->setFlag(1);
   int fd2 = open("../C.txt", O_CREAT | O_APPEND | O_RDWR, 0644);
   std::thread th2(&SensorPluginBase::dataProcess, t2, fd2, aa);
   if (th2.joinable())
   {
      th2.detach();
   }
   sleep(200);
   //stop the get data.
   t1->setFlag(0);
   t2->setFlag(0);
   t2->startThread();
   //下面保留一个延迟函数,确保main线程不会结束,否则前面创建的2个线程会随着main线程的结束而退出!
   getchar();

   close(fd1);
   //close(fd2);
   cout << "main thread exit()" << endl;
}

CMakeLists.txt

cmake_minimum_required (VERSION 2.6)
  project (sensorPluginTest) 

include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread")#必须加上-pthread
elseif(COMPILER_SUPPORTS_CXX0X)
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
     message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()

set(${PROJECT_NAME}_HDRS
  include/sensorPluginBase.h
  include/b.h
  include/c.h
  include/label.h
  include/constParam.h
)
  include_directories (./include "${PROJECT_SOURCE_DIR}/include")

  FILE(GLOB SRC_LIST_CPP "${PROJECT_SOURCE_DIR}/src/*.cpp")
  FILE(GLOB SRC_LIST_C "${PROJECT_SOURCE_DIR}/src/*.c")


set(LINK_DIR ${PROJECT_SOURCE_DIR}/lib/ )
set(CONSOLE_DIR /lib/x86_64-linux-gnu/)

link_directories(${LINK_DIR} ${CONSOLE_DIR})

  add_executable (main test/main.cpp src/b.cpp src/c.cpp src/label.cpp)
#如果不生成动态库,则下面这个target_link_libraries也删掉。
  target_link_libraries( main optimized
    libclass_loader.so
    libconsole_bridge.so
 )
#下面的语句就是生成动态库,如果不需要,则删掉,同时删掉c.cpp和b.cpp中的导出函数那句话
  add_library(bsensorplugin SHARED src/b.cpp src/label.cpp include/sensorPluginBase.h include/b.h)
  
  target_link_libraries( bsensorplugin optimized
    libclass_loader.so
    libconsole_bridge.so
 )

 add_library(csensorplugin SHARED src/c.cpp src/label.cpp include/sensorPluginBase.h include/c.h)
  
  target_link_libraries( csensorplugin optimized
    libclass_loader.so
    libconsole_bridge.so
    
 )

如果要使用class_loader导出成插件,则需要将class_loaderd源码包中的include下的class_loader目录都放到本工程的include之下。同时需要将class_loaderd源码包编译出来的libclass_loader.so放到本工程的lib/之下。

工程结构如下:B.txt是程序运行之后写入的数据。

 运行截图:

最后,我们这里是给出一个示例,没有考虑线程安全的问题,实际上使用了detach()后,我们就无法控制线程的执行了,如果线程执行完之后, 我们传进去的参数如果是指针,则指针可能释放了,会造成线程不安全的问题。具体的原因参见:https://blog.csdn.net/weixin_42570248/article/details/100810323

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值