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