当前位置: 首页 > news >正文

c/c++开发,无可避免的模板编程实践(篇八)

一、借用标准库模板构造自己的模板

        通常,模板设计是遵循当对象的类型不影响类中函数的行为时就使用模板。这也就是为何标准库提供大部分的模板都是与容器、迭代器、适配器、通用算法等有关,因为这些主要是除了对象集合行为,如读写、增删、遍历、排序、比较等大多与对象类型无关的逻辑行为。

        在实际项目中,本人建议大家在使用模板时,采用的最好模板设计方式是走适配器方法,就像标准库基于vector、list、deque这些基准容器,通过适配封装去实现stack、queue、priority queue这些容器适配器一样。我们根据自己项目需要,采用标准库提供的容器及算法,创建自己的类模板应用到项目中。

二、基于标准库模板创建自定义类模板案例

        2.1 自定义容器适配器

        在本文中,将设计一个日志消息队列的容器适配器,基于双端队列(deque)容器和互斥锁,通过适配,创建一个线程安全的消息队列类模板。该消息队列类通过二次封装,实现数据末端添加数据,头部取出数据,队列大小有限制的跨线程安全消息缓冲区。

        首先创建一个queuedata.h和queuedata.cpp源文件,在queuedata.h文件实现消息队列类模板进行声明,在queuedata.cpp源文件进行定义,在queuedata.h文件末通过#include "queuedata.cpp"引用定义内容。本文中,QueueData类模板虽然说类似容器适配器,但是没有提供配套的迭代器iterator,大家感兴趣的可以自行实现一下(就是将deque容器的迭代器iterator做一下中转即可)。

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000#ifndef _QUEUE_DATA_H_
#define _QUEUE_DATA_H_/************************************************************************Copyright 2023-02-06, pyfree**File Name       : queuedata.h*File Mark       : *Summary         : *数据队列类模板,线程安全,对std::deque进行适配,通过PYMutex锁约束线程安全,提供数据增删等功能接口**Current Version : 1.00*Author          : pyfree*FinishDate      :**Replace Version :*Author          :*FinishDate      :************************************************************************/
#include <deque>
#include <queue>
#include <stdio.h>
#include <string.h>
#include <string>#include "Mutex.h"template <class T>
class QueueData
{
public:QueueData(std::string desc = "thread_queue");~QueueData();///*** 获取队列大小* @return {int } 队列大小*/int size();/*** 判定队列是否为空* @return {bool } 是否为空队列*/bool isEmpty();/*** 获取队列头元素* @param it {T&} 头元素* @return {bool } 是否成功*/bool getFirst(T &it);/*** 删除元素* @return {bool } 是否成功*/bool removeFirst();/*** 获取队列头元素,并从队列终删除* @param it {T&} 头元素* @return {bool } 是否成功*/bool pop(T &it);/*** 从队列头开始逐步获取多个元素,并剔除* @param its {queue<T>&} 获取到的元素集* @param sizel {int} 一次获取多少个* @return {bool } 至少获取一个元素以上则成功*/bool getList(std::queue<T> &its,unsigned int sizel=5);/*** 从队列尾部添加元素* @param it {T} 被添加元素* @return {void } 无返回*/void add(T it);/*** 从队列头部添加元素* @param it {T} 被添加元素* @return {void } 无返回*/void add_front(T it);/*** 清空元素* @return {void }*/void clear();
private:void init();QueueData& operator=(const QueueData&) {return this;};
protected:std::string queue_desc;
private:/点集转发//协议解析结果缓存std::deque<T> datacache_queue;	//队列容器PYMutex m_Mutex;				//线程锁,或者如果更彻底采用acl库,采用acl::thread_mutex替代//static unsigned int QSize;		//队列大小约束,超出是会从队列头剔除旧数据腾出空位在对末添加数据//int queue_overS;				//队列溢出次数计数
};#include "queuedata.cpp"#endif //_QUEUE_DATA_H_

       2.2 非类型模板参数的结构体模板

         传入消息队列类的信息是一个非类型模板参数的结构体模板,可以根据实际项目需要选择消息缓存区最大字节数。创建LogDef.h源文件,实现消息结构体模板,并定义日志等级枚举值。该结构体在定义对象时可以采用默认的方法MyLogStruct<> obj,也可以指定大小MyLogStruct<DATA_SIZE_MAX_LEVLE2> obj,或指定任意值作为缓存区域大小,MyLogStruct<100> obj。

#ifndef _LOG_DEF_H_
#define _LOG_DEF_H_
/************************************************************************Copyright 2023-02-06, pyfree**File Name       : LogDef.h*File Mark       : *Summary         : Log线程类使用到的日志等级枚举类型,日志信息格式-用于日志缓冲区存放日志的结构体**Current Version : 1.00*Author          : pyfree*FinishDate      :**Replace Version :*Author          :*FinishDate      :************************************************************************/
#ifdef __linux__
#include <string.h>
#endif typedef enum eLogType 
{eLog_DEBUG			= 1,eLog_TRACE			= 2,eLog_NOTICE			= 3,eLog_WARNING 		= 4,eLog_ERROR			= 5
}LogLevel;#define DATA_SIZE_MAX_LEVLE1 	1024	//日志缓存信息空间大小(1024字节)
#define DATA_SIZE_MAX_LEVLE2 	512		//日志缓存信息空间大小(512字节)
#define DATA_SIZE_MAX_LEVLE3 	256		//日志缓存信息空间大小(256字节)//日志缓存信息结构体,采用结构体默认赋值
template<int SIZE = DATA_SIZE_MAX_LEVLE3>
struct MyLogStruct
{MyLogStruct():type(0){memset(szBuffer, 0, SIZE);};int 	type;char	szBuffer[SIZE];
};#endif //_LOG_DEF_H_

        2.3 日志记录类设计

        下来就是日志记录功能部分,创一个日志类,该类有一个QueueData<MyLogStruct<> > logs_cache对象用来缓存日志。该日志类还是一个单体模式设计,并继承一个线程类。线程循环体内,日志对象会不断去读取缓存区内的日志信息,如果读取到信息,就写入到日志文件内。另外,为了方式日志记录过大造成磁盘存储空间不足,将有一个DiskSpaceMgr类对象来定期巡检磁盘剩余空间,在存储空间不足时,去删除旧的日志信息。

        创建Log.h和Log.cpp源文件,Log.h源文件如下:

#ifndef _CLOGGER_H_
#define _CLOGGER_H_
/************************************************************************Copyright 2023-02-06, pyfree**File Name       : Log.h*File Mark       : *Summary         : Log写入独立线程类,提供添加日志信息进入缓存接口,自身不断从缓存读取日志信息写入文件*					会启动一个磁盘空间管理线程对象DiskSpaceMgr,在磁盘空间不足时,删除旧日志**Current Version : 1.00*Author          : pyfree*FinishDate      :**Replace Version :*Author          :*FinishDate      :************************************************************************/
#include "myThread.h"
#include "LogDef.h"
#include "queuedata.h"class DiskSpaceMgr;class CLogger : public MyThread
{
public:void Log(const eLogType type, const char* lpszFormat, ...);static CLogger* createInstance( void );
private:CLogger();~CLogger();int Run();void WriteLog( const int iMsgType, const char * strMsg);void WriteLogToFile( std::string strPath,std::string strTime,const char * strMsg);std::string createFileName(std::string strTime_);std::string strTime();std::string createLogTimeAndTypeDesc(const unsigned int iMsgType, std::string strTime_);
private:static CLogger* m_pLogInstance;bool running;FILE * fpLog;std::string cur_log_path;//for cacheQueueData<MyLogStruct<> > logs_cache;//DiskSpaceMgr *disk_space_mgr;
};
#endif //_CLOGGER_H_

       2.4 磁盘剩余空间管理类

         对象DiskSpaceMgr *disk_space_mgr是由Logger类创建的,该磁盘空间管理类是继承了类线程类的,在线程循环体内,不间断地巡检指定磁盘的剩余空间是否小于限定空间大小,小于时,将按配置要求去删除旧的日志信息。

        创建spaceMgr.h和spaceMgr.cpp源文件,spaceMgr.h内容如下:

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000#ifndef _SPACE_MGR_H_
#define _SPACE_MGR_H_
/************************************************************************Copyright 2023-02-06, pyfree**File Name       : spaceMgr.h*File Mark       : *Summary         : 磁盘空间巡检线程类,根据预留空间要求删除app日志文件**Current Version : 1.00*Author          : pyfree*FinishDate      :**Replace Version :*Author          :*FinishDate      :************************************************************************/
#ifdef linux
#include <string>
#endif
#include <vector>#include "myThread.h"class DiskSpaceMgr : public MyThread
{
public:/*** 构造函数,如传入参数D 2000 log log,则指明当D盘空闲空间不足2000M时,删除当前目录/log下的log(后缀)文件* @param disk_ {char} 指定盘符* @param fsl_ {int} 预留空间大小,单位MB* @param dir_ {string} 指定目录* @param ext_ {string} 扩展名* @return { } */DiskSpaceMgr(char disk_, int fsl_,std::string dir_="log",std::string ext_="log");virtual ~DiskSpaceMgr(void);int Run();void add(std::string dir_,std::string ext_);
private:struct DelInfo{DelInfo(std::string dir_,std::string ext_): dir(dir_), ext(ext_){};std::string dir;std::string ext;};
private://用于日志删除std::vector<DelInfo> dirs;  //存储目录char DiskStr;         //日志存储磁盘int freeSizeLimit;    //磁盘预留空间要求
};#endif

        2.5 其他辅助类及函数设计

        日志类及磁盘管理类都继承了线程类MyThread,是通过myThread.h和myThread.cpp声明定义的,myThread.h内容如下:

#ifndef _MYTHREAD_H
#define _MYTHREAD_H
/************************************************************************Copyright 2023-02-06, pyfree**File Name       : myThread.h*File Mark       : *Summary         : *支持windows和linux的线程类,提供基本的线程功能(循环、启动、退出)**Current Version : 1.00*Author          : pyfree*FinishDate      :**Replace Version :*Author          :*FinishDate      :************************************************************************/
#ifdef WIN32
#include <process.h>
#include <iostream>typedef void* HANDLE_THREAD;
#else
#include <pthread.h>
#include <unistd.h>typedef pthread_t HANDLE_THREAD;
#endifclass MyThread
{
public://funcMyThread();                     // constructed function~MyThread();/*** the entity for thread running* @param null {void } 无参数* @return {int} 运行返回结果*/virtual int Run()=0;/*** start thread* @param null {void } 无参数* @return {bool} 是否启动成功*/bool start();/*** get thread ID* @param null {void } 无参数* @return {HANDLE_THREAD} 线程句柄*/HANDLE_THREAD getThreadID();
#ifdef __linux__//get thread statusint getState();//wait for thread endvoid join();//wait for thread end in limit timevoid join(unsigned long millisTime);
#endif
public://val
#ifdef __linux__//threadStatus-new createstatic const int THREAD_STATUS_NEW = 0;//threadStatus-runningstatic const int THREAD_STATUS_RUNNING = 1;//threadStatus-endstatic const int THREAD_STATUS_EXIT = -1;
#endif
private://func
#ifdef WIN32static void agent(void *p);
#else//get manner pointer of execution static void* run0(void* pVoid);//manner of execution insidevoid* run1();
#endif
private://valHANDLE_THREAD hThread;
#ifdef __linux__//thread statusint threadStatus;
#endif
};#endif /* _MYTHREAD_H */

        消息队列类在队列内容进行变更时,需要通过互斥锁确保跨线程操作安全,互斥锁是由Mutex.h和Mutex.cpp源文件声明定义的,Mutex.h内容如下:

#ifndef PYMUTEX_H
#define PYMUTEX_H#ifdef WIN32
//#include <windows.h>
#else
#include <pthread.h>
#endiftypedef void *HANDLE;class IMutex
{
public:virtual ~IMutex() {}virtual void Lock() const = 0;virtual bool TryLock() const = 0;virtual void Unlock() const = 0;
};class PYMutex : public IMutex
{
public:PYMutex();~PYMutex();virtual void Lock() const;virtual bool TryLock() const;virtual void Unlock() const;
private:
#ifdef _WIN32HANDLE m_mutex;
#elsemutable pthread_mutex_t m_mutex;
#endif
};#endif //PYMUTEX_H

        磁盘管理类,在进行磁盘信息读取和文件删除时,是借用了DiskSpace.h和DiskSpace.cpp源文件声明定义的磁盘空间统计和日志删除相关函数集来实现的,DiskSpace.h内容如下:

#ifndef DISK_SPACE_H
#define DISK_SPACE_H/************************************************************************Copyright 2023-02-06, pyfree**File Name       : DiskSpace.h*File Mark       : *Summary         : *磁盘空间统计和日志删除相关函数集*Current Version : 1.00*Author          : pyfree*FinishDate      :**Replace Version :*Author          :*FinishDate      :************************************************************************/#include <string>namespace pyfree
{/*** 根据指定磁盘获取磁盘的总空间和剩余空间* @param _DiskStr {char} 磁盘目录,一般win指定{C,D},linux指定{/}* @param _totalSize {int} 返回磁盘总空间* @param _freeSize {int} 返回磁盘剩余空间* @return {int} 预留的返回值,暂指定是常量1*/int getDiskFreeSpace(char _DiskStr, int &_totalSize, int &_freeSize);/*** 根据指定目录 扩展名 天数限制等删除目录下的文件,项目用于删除旧日志操作* @param _dir {string}} 目录* @param extname {string} 扩展名,如txt/ini/log等* @param dayForLimit_ {int} 指定天数,默认为0时会删除非当天的其他文件* @return {void} 无返回*/void moveOldFile(std::string _dir, const std::string &extname, int dayForLimit_=0);/*** 获取当天凌晨时刻的偏移时间,单位秒,与1970-01-01 00:00:00起* @param deviation {int} 偏移秒数* @return {int} 当天凌晨时刻的偏移时间.单位秒*/int getCurDayZeroClockTime(int deviation=0);
};#endif

三、工程结构及编程测试

       3.1 工程目录结构

         按上述源文件设计,给出组织这些源文件的工程目录结构:

log_testbin                #测试程序输出build_win          #win编译中间文件存储build_linux        #Linux编译中间文件存储srcDiskSpace.h    #磁盘访问、文件删除等功能实现DiskSpace.cppLog.h          #日志类,单体模式,继承线程类Log.cppLogDef.h       #日志信息定义Mutex.h        #互斥锁Mutex.cppmyThread.h     #线程类myThread.cpppysleep.h      #线程睡眠等待统一宏转换设计queuedata.h    #消息队列类模板queuedata.cppspaceMgr.h     #磁盘空间管理类,继承线程类spaceMgr.cpptestmain.cpp      #测试程序代码CMakeLists.txt    #cmake工程compile.txt       #工程编译指令

        3.2 cmake工程配置

        CMakeLists.txt,cmake工程配置文件

# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (log_test)
#
if(WIN32)message(STATUS "windows compiling...")add_definitions(-D_PLATFORM_IS_WINDOWS_)set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")set(WIN_OS true)
else(WIN32)message(STATUS "linux compiling...")add_definitions( -D_PLATFORM_IS_LINUX_)add_definitions("-Wno-invalid-source-encoding")# add_definitions("-O2")set(UNIX_OS true)set(_DEBUG true)endif(WIN32)#
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)# 指定源文件的目录,并将名称保存到变量
SET(source_h${PROJECT_SOURCE_DIR}/src/pysleep.h${PROJECT_SOURCE_DIR}/src/Mutex.h${PROJECT_SOURCE_DIR}/src/myThread.h${PROJECT_SOURCE_DIR}/src/queuedata.h${PROJECT_SOURCE_DIR}/src/LogDef.h${PROJECT_SOURCE_DIR}/src/Log.h${PROJECT_SOURCE_DIR}/src/DiskSpace.h${PROJECT_SOURCE_DIR}/src/spaceMgr.h)SET(source_cpp#${PROJECT_SOURCE_DIR}/src/Mutex.cpp${PROJECT_SOURCE_DIR}/src/myThread.cpp${PROJECT_SOURCE_DIR}/src/Log.cpp${PROJECT_SOURCE_DIR}/src/DiskSpace.cpp${PROJECT_SOURCE_DIR}/src/spaceMgr.cpp${PROJECT_SOURCE_DIR}/test/main.cpp)#头文件目录
include_directories(${PROJECT_SOURCE_DIR}/src)if (${UNIX_OS})add_definitions("-W""-fPIC""-Wall"# "-Wall -g""-Werror""-Wshadow""-Wformat""-Wpointer-arith""-D_REENTRANT""-D_USE_FAST_MACRO""-Wno-long-long""-Wuninitialized""-D_POSIX_PTHREAD_SEMANTICS""-DACL_PREPARE_COMPILE""-Wno-unused-parameter""-fexceptions")set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0")link_directories()
# 指定生成目标
add_executable(log_test ${source_h} ${source_cpp})
#link
target_link_libraries(log_test -lpthread -pthread -lz -lrt -ldl
)endif(${UNIX_OS})if (${WIN_OS})set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4819")add_definitions("-D_CRT_SECURE_NO_WARNINGS""-D_WINSOCK_DEPRECATED_NO_WARNINGS""-DNO_WARN_MBCS_MFC_DEPRECATION""-DWIN32_LEAN_AND_MEAN"
)link_directories()if (CMAKE_BUILD_TYPE STREQUAL "Debug")set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_SOURCE_DIR}/bin)
# 指定生成目标
add_executable(log_testd ${source_h} ${source_cpp})else(CMAKE_BUILD_TYPE)set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/bin)
# 指定生成目标
add_executable(log_test ${source_h} ${source_cpp})endif (CMAKE_BUILD_TYPE)endif(${WIN_OS})

        compile.txt,编译指令指示文件

win:
cd log_test && mkdir build_win && cd build_win
cmake -G "Visual Studio 10 2010 Win64" -DCMAKE_BUILD_TYPE=Release ..
msbuild log_test.sln /p:Configuration="Release" /p:Platform="x64"cmake -G "Visual Studio 10 2010 Win64" -DCMAKE_BUILD_TYPE=Debug ..
msbuild log_test.sln /p:Configuration="Debug" /p:Platform="x64"Linux:
cd log_test
mkdir build_linux
cd build_linux
cmake ..
make

           3.3 日志类调用,测试案例

         测试工程文件main.cpp:

#include <stdio.h>
#include <stdlib.h>#include "pysleep.h"
#include "Log.h"namespace GlobalVar {extern char disk_DescStr;				//磁盘名extern unsigned int disk_space_limit;	//剩余空间限制为*MBextern std::string logdir;				//后期记录日志目录重配置文件读取extern std::string logname;				//可设置为服务名extern std::string log_ext_flag;		//日志扩展名
};
//log_test.exe D 2000 log log
//log_test.exe D 
void arg_analysis(int argc, char *argv[]);int main(int argc, char *argv[])
{arg_analysis(argc,argv);int i = 0;while(i<100){CLogger::createInstance()->Log(LogLevel(rand()%5),"log test for [%d]",i++);pysleep(10);}//while(1){pysleep(10);}return 0;
}void arg_analysis(int argc, char *argv[])
{for(int index=0; index<argc; index++){switch(index){case 0:{#ifdef WIN32std::string appname = std::string(argv[0]);GlobalVar::logname = appname.substr(0,appname.length()-4);#elseGlobalVar::logname = std::string(argv[0]);#endif}break;case 1:{GlobalVar::disk_DescStr = argv[1][0];}break;case 2:{GlobalVar::disk_space_limit = static_cast<unsigned int>(atoi(argv[2]));}break;case 3:{GlobalVar::logdir = std::string(argv[3]);}break;case 4:{GlobalVar::log_ext_flag = std::string(argv[4]);}break;default:break;}}	
}

        3.4 编译及测试

        win:

         linux:

 四、补充源码

        部分源码前面已经给出(头文件),下面给出其他源码文件:

         pysleep.h

#ifndef _PY_SLEEEP_H_
#define _PY_SLEEEP_H_#ifdef WIN32
#include <windows.h>
#define pysleep(x) Sleep(x)
#else
#define pysleep(x) usleep(1000*x)
#endif#endif //_PY_SLEEEP_H_

        DiskSpace.cpp

#include "DiskSpace.h"#include <time.h>
#include <list>
#include <vector>#ifdef WIN32
#include <io.h>
#include <direct.h>
#include <Windows.h>
#else
#include <sys/statfs.h>
#include <dirent.h>
/*#include <sys/vfs.h> or <sys/statfs.h> */
#include <sys/vfs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#endif#include "Log.h"int pyfree::getDiskFreeSpace(char _DiskStr, int &_totalSize, int &_freeSize)
{
#ifdef WIN32BOOL fResult;unsigned _int64 i64FreeBytesToCaller;unsigned _int64 i64TotalBytes;unsigned _int64 i64FreeBytes;char dir[4] = { _DiskStr, ':', '\\' };fResult = GetDiskFreeSpaceEx(dir,(PULARGE_INTEGER)&i64FreeBytesToCaller,(PULARGE_INTEGER)&i64TotalBytes,(PULARGE_INTEGER)&i64FreeBytes);//GetDiskFreeSpaceEx function,get the disk space status,return BOOL type    if (fResult)//jude the disk is in work status by the return value   {_totalSize = static_cast<int>(static_cast<float>(i64TotalBytes) / 1024 / 1024);_freeSize = static_cast<int>(static_cast<float>(i64FreeBytesToCaller) / 1024 / 1024);//std::cout << " totalspace:" << _totalSize << " MB" << std::endl;//disk total size    //std::cout << " freespace:" << _freeSize << " MB" << std::endl;//disk free space sze   }
#endif // WIN32
#ifdef __linux__//printf("DiskFlag(%c)\n", _DiskStr);struct statfs diskInfo;statfs("/", &diskInfo);unsigned long long totalBlocks = diskInfo.f_bsize;unsigned long long totalSize = totalBlocks * diskInfo.f_blocks;_totalSize = static_cast<int>(totalSize >> 20);//printf("TOTAL_SIZE == %d MB\n", _totalSize);unsigned long long freeDisk = diskInfo.f_bfree*totalBlocks;_freeSize = static_cast<int>(freeDisk >> 20);//printf("DISK_FREE == %d MB\n", _freeSize);
#endifreturn 1;
}//delete old file which is older taday for the file modify time
void pyfree::moveOldFile(std::string _dir, const std::string &extname, int dayForLimit_)
{try{
#ifdef WIN32_finddata_t fileInfo;intptr_t hFile;std::string filter = _dir;if (filter[filter.size() - 1] != '//' || filter[filter.size() - 1] != '\\') {filter.push_back('\\');}filter += "*.";filter += extname;//time_t file_time_ = time(NULL);time_t file_time_ = (time_t)getCurDayZeroClockTime(dayForLimit_*86400);//gethFile = _findfirst(filter.c_str(), &fileInfo);if (hFile == -1) {return;}std::string delOldFile = "";//find the oldest file by modify time do {if (extname.empty())//no ext name, that is dir{if ((fileInfo.attrib & _A_SUBDIR)) {if (0 == strcmp(fileInfo.name, ".") || 0 == strcmp(fileInfo.name, "..")){continue;}}}//if(fileInfo.time_write<_time)//modify timeif (fileInfo.time_create<file_time_)//create time{file_time_ = fileInfo.time_create;delOldFile = _dir + "//" + (std::string(fileInfo.name));}} while (_findnext(hFile, &fileInfo) == 0);_findclose(hFile);
#endif#ifdef linux//printf("moveOldFile(*.%s) 1 from(%s) \n",extname.c_str(),_dir.c_str());std::string curdir = _dir;if (curdir[curdir.size() - 1] != '/') {curdir.push_back('/');}DIR *dfd;if ((dfd = opendir(curdir.c_str())) == NULL){CLogger::createInstance()->Log(eLog_WARNING,"open %s error with msg is: %s\n", curdir.c_str(), strerror(errno));return;}struct dirent    *dp;//time_t file_time_ = time(NULL);time_t file_time_ = (time_t)getCurDayZeroClockTime(dayForLimit_ * 86400);std::string delOldFile = "";while ((dp = readdir(dfd)) != NULL){if (extname.empty())//no ext name, that is dir{if (dp->d_type == DT_DIR) {if (0 == strcmp(dp->d_name, ".") || 0 == strcmp(dp->d_name, "..")){continue;}}}else {if (NULL == strstr(dp->d_name, extname.c_str())){continue;}}std::string _path = _dir + "/";_path += dp->d_name;struct stat el;stat(_path.c_str(), &el);if (el.st_mtime<file_time_) {file_time_ = el.st_mtime;delOldFile = _path;}}if (NULL != dp) {delete dp;dp = NULL;}if (NULL != dfd) {closedir(dfd);dfd = NULL;}
#endifif (!delOldFile.empty()){//printf("get old file: %s \n", delOldFile.c_str());int ret = remove(delOldFile.c_str());if (0 != ret) {CLogger::createInstance()->Log(eLog_WARNING,"can't remove %s \n", delOldFile.c_str());}else{CLogger::createInstance()->Log(eLog_NOTICE,"success remove %s \n", delOldFile.c_str());}}}catch(...){CLogger::createInstance()->Log(eLog_ERROR,"moveOldFile(*.%s) from(%s) exception error\n",extname.c_str(),_dir.c_str());}
}int pyfree::getCurDayZeroClockTime(int deviation)
{int ZeroClockTime_ = 0;time_t cur_time_ = time(NULL);struct tm _tt;
#ifdef WIN32localtime_s(&_tt, &cur_time_);
#elselocaltime_r(&cur_time_,&_tt);
#endif//当日凌晨时刻_tt.tm_hour = 0;_tt.tm_min = 0;_tt.tm_sec = 0;ZeroClockTime_ = static_cast<int>(mktime(&_tt));ZeroClockTime_ -= deviation;//偏移时间return ZeroClockTime_;
}

        Log.cpp

#include "Log.h"
#include <time.h>
#include <sys/timeb.h>#include <stdio.h>
#include <stdarg.h>
#include <string>#ifdef __linux__
#include <string.h>
#include <unistd.h>
#include <stdlib.h>#ifndef sprintf_s
#define sprintf_s sprintf
#endif#else	//WIN32#ifndef vsnprintf
#define vsnprintf vsnprintf_s
#endif 
#endif#include "pysleep.h"
#include "spaceMgr.h"namespace GlobalVar
{char disk_DescStr  = 'D';		//磁盘名unsigned int disk_space_limit = 2000;	//剩余空间限制为*MB,少于该值去删除日志释放空间std::string logdir = "log";		//后期记录日志目录重配置文件读取std::string logname = "pyfree";	//可设置为服务名std::string log_ext_flag = "log";//日志扩展名
};CLogger* CLogger::m_pLogInstance = NULL;
CLogger::CLogger() : running(true), fpLog(NULL), cur_log_path("log")
{char buf[256] = {0};sprintf_s(buf,"mkdir %s",GlobalVar::logdir.c_str());system(buf);this->start();disk_space_mgr = new DiskSpaceMgr(GlobalVar::disk_DescStr,GlobalVar::disk_space_limit,GlobalVar::logdir,GlobalVar::log_ext_flag);disk_space_mgr->start();
};CLogger::~CLogger()
{delete disk_space_mgr;disk_space_mgr = NULL;running = false;if (NULL != fpLog){fclose(fpLog);fpLog = NULL;}
};CLogger* CLogger::createInstance( void )
{if (m_pLogInstance == NULL){m_pLogInstance = new CLogger();return m_pLogInstance;}elsereturn m_pLogInstance;
};int CLogger::Run()
{MyLogStruct<> log_item;while (running) {if(logs_cache.pop(log_item)){WriteLog(log_item.type, log_item.szBuffer);#ifdef _DEBUG#ifndef WIN32printf("Log::[%d]-->%s\n", getpid(), log_item.szBuffer);#elseprintf("Log::-->%s\n", log_item.szBuffer);#endif //WIN32#endif //_DEBUG}pysleep(1);}return 0;
};void CLogger::Log(const eLogType type, const char* lpszFormat, ...)
{va_list args;MyLogStruct<> log_item;log_item.type = static_cast<int>(type);va_start(args, lpszFormat);vsnprintf(log_item.szBuffer, sizeof(log_item.szBuffer), lpszFormat, args);va_end(args); logs_cache.add(log_item);
}void CLogger::WriteLog( const int iMsgType, const char * strMsg)
{try {//system time to stringstd::string strTime_ = strTime();//file namestd::string strPath = createFileName(strTime_.substr(0,10));	// log time and type descstd::string strTimeAndTypeDesc = createLogTimeAndTypeDesc(iMsgType, strTime_);WriteLogToFile(strPath,strTimeAndTypeDesc,strMsg);}catch (...) {printf("write log[%d]{%s}error\n", iMsgType, strMsg);}
}void CLogger::WriteLogToFile( std::string strPath,std::string strTime_,const char * strMsg)
{if(cur_log_path!=strPath||NULL == fpLog){if (NULL != fpLog){fclose(fpLog);fpLog = NULL;}			//open#ifdef WIN32fopen_s(&fpLog, strPath.c_str(), "a+");#elsefpLog = fopen(strPath.c_str(), "a+");#endif}if (NULL != fpLog){fseek(fpLog, 0, SEEK_END);fwrite(strTime_.c_str(), strTime_.length(), 1, fpLog);fwrite(strMsg, strlen(strMsg), 1, fpLog);fwrite("\n", 1, 1, fpLog);}
}std::string CLogger::createFileName(std::string strTime_)
{//file namestd::string strPath = GlobalVar::logdir;	
#ifdef WIN32strPath += "\\";
#elsestrPath += "/";
#endifstrPath += strTime_;strPath += "_";strPath += GlobalVar::logname;strPath += ".log";return strPath;
}std::string CLogger::strTime()
{time_t tt;struct timeb tm0;struct tm tm1;char buf[64];ftime(&tm0);tt = tm0.time;
#ifdef WIN32localtime_s(&tm1, &tt);
#elselocaltime_r(&tt, &tm1);
#endifsprintf_s(buf, "%04d-%02d-%02d %02d:%02d:%02d.%03d ", tm1.tm_year + 1900, tm1.tm_mon + 1, tm1.tm_mday, tm1.tm_hour, tm1.tm_min, tm1.tm_sec, tm0.millitm);std::string strTime_ = buf;buf[10] = '\0';return strTime_;
}
//日志等级枚举值的字符串描述
std::string eLogTypeDesc[6] = {"[UNKNOWN] ","[eLog_DEBUG] ","[eLog_TRACE] ","[eLog_NOTICE] ","[eLog_WARNING] ","[eLog_ERROR] "};std::string CLogger::createLogTimeAndTypeDesc(const unsigned int iMsgType, std::string strTime_)
{std::string strTimeAndTypeDesc = strTime_;unsigned int msg_type = iMsgType;if(msg_type>6) msg_type = 0;	//非枚举值外的均为未知strTimeAndTypeDesc += eLogTypeDesc[msg_type];return strTimeAndTypeDesc;
};/*以下是LogFunction*/
/*
*在queuedata.cpp中应用,该函数主要用来解决QueueData类嵌套调用CLogger的异常问题:
*“嵌套名指定中使用了不完全的类型”
*/
void reportLogCacheOver(const char *queue_desc,int size)
{//每溢出10次,报告一次CLogger::createInstance()->Log(eLog_WARNING,"add item to queue %s, but the size of QueueData is up to limmit size: %d.\n", queue_desc, size);	
}

        Mutex.cpp

#include "Mutex.h"#ifdef WIN32
#include <windows.h>
#endif
//#include <iostream>
#include <stdio.h>PYMutex::PYMutex()
{
#ifdef _WIN32m_mutex = ::CreateMutex(NULL, FALSE, NULL);
#elsepthread_mutex_init(&m_mutex, NULL);
#endif
}PYMutex::~PYMutex()
{
#ifdef _WIN32::CloseHandle(m_mutex);
#elsepthread_mutex_destroy(&m_mutex);
#endif
}void PYMutex::Lock() const
{
#ifdef _WIN32//DWORD d = WaitForSingleObject(m_mutex, INFINITE);WaitForSingleObject(m_mutex, INFINITE);/// \todo check 'd' for result
#elsepthread_mutex_lock(&m_mutex);
#endif
}bool PYMutex::TryLock() const
{
#ifdef _WIN32DWORD dwWaitResult = WaitForSingleObject(m_mutex, 0);  if (dwWaitResult != WAIT_OBJECT_0 && dwWaitResult != WAIT_TIMEOUT) {printf("thread WARNING: bad result from try-locking mutex\n");}return (dwWaitResult == WAIT_OBJECT_0) ? true : false; 
#elsereturn (0==pthread_mutex_trylock(&m_mutex))?true:false;
#endif	
};void PYMutex::Unlock() const
{
#ifdef _WIN32::ReleaseMutex(m_mutex);
#elsepthread_mutex_unlock(&m_mutex);
#endif
}

        myThread.cpp

#include "myThread.h"#ifdef WIN32
#include <windows.h>
#else
#include <stdio.h>
#endif MyThread::MyThread()
{#ifdef __linux__hThread = 0;threadStatus = THREAD_STATUS_NEW;#endif
}MyThread::~MyThread()
{#ifdef WIN32WaitForSingleObject(hThread, INFINITE);#elsejoin(10);#endif
}int MyThread::Run()
{#ifdef WIN32printf("Base Thread\n");#elsewhile(true){printf("thread is running!\n");sleep(100);}#endifreturn 0;
}bool MyThread::start()
{#ifdef WIN32return NULL!=(hThread =(HANDLE_THREAD)_beginthread(agent, 0, (void *)this));#elsereturn pthread_create(&hThread, NULL, run0, this) == 0;#endif
}HANDLE_THREAD MyThread::getThreadID()
{return hThread;
}#ifdef WIN32
void MyThread::agent(void *p)
{MyThread *agt = (MyThread *)p;agt->Run();
}#else
void* MyThread::run0(void* pVoid)
{MyThread* p = (MyThread*) pVoid;p->run1();return p;
}void* MyThread::run1()
{threadStatus = THREAD_STATUS_RUNNING;hThread = pthread_self();Run();threadStatus = THREAD_STATUS_EXIT;hThread = 0;pthread_exit(NULL);
}int MyThread::getState()
{return threadStatus;
}void MyThread::join()
{if (hThread > 0){pthread_join(hThread, NULL);}
}void MyThread::join(unsigned long millisTime)
{if (hThread == 0){return;}if (millisTime == 0){join();}else{unsigned long k = 0;while (threadStatus != THREAD_STATUS_EXIT && k <= millisTime){usleep(100);k++;}}
}
#endif

        queuedata.cpp

#include "queuedata.h"#include "LogDef.h"
#include "Log.h"extern void reportLogCacheOver(const char*,int);template <class T>
unsigned int  QueueData<T>::QSize = 100;template <class T>
QueueData<T>::QueueData(std::string desc): queue_desc(desc)
{init();
};template <class T>
void QueueData<T>::init() 
{queue_overS = 0;
};template <class T>
QueueData<T>::~QueueData()
{}//
template <class T>
int QueueData<T>::size()
{int ret = 0;m_Mutex.Lock();ret = static_cast<int>(datacache_queue.size());m_Mutex.Unlock();return ret;
}template <class T>
bool QueueData<T>::isEmpty()
{bool ret = false;m_Mutex.Lock();ret = datacache_queue.empty();m_Mutex.Unlock();return ret;
}template <class T>
bool QueueData<T>::getFirst(T &it) 
{bool ret = false;m_Mutex.Lock();if (!datacache_queue.empty()) {it = datacache_queue.front();ret = true;}m_Mutex.Unlock();return ret;
}template <class T>
bool QueueData<T>::removeFirst() 
{bool ret = false;m_Mutex.Lock();if (!datacache_queue.empty()) {datacache_queue.pop_front();ret = true;}m_Mutex.Unlock();return ret;
}template <class T>
bool QueueData<T>::pop(T &it)
{bool ret = false;m_Mutex.Lock();if (!datacache_queue.empty()) {it = datacache_queue.front();datacache_queue.pop_front();ret = true;}m_Mutex.Unlock();return ret;
};template <class T>
bool QueueData<T>::getList(std::queue<T> &its,unsigned int sizel)
{m_Mutex.Lock();while (!datacache_queue.empty()){its.push(datacache_queue.front());datacache_queue.pop_front();if (its.size() >= sizel){break;}}m_Mutex.Unlock();return !its.empty();
};template <class T>
void QueueData<T>::add(T it) 
{m_Mutex.Lock();if (datacache_queue.size() > QSize) {queue_overS++;datacache_queue.pop_front();}datacache_queue.push_back(it);m_Mutex.Unlock();if (queue_overS >= 10) {//每溢出10次,报告一次reportLogCacheOver(queue_desc.c_str(),QSize);queue_overS = 0;}
}template <class T>
void QueueData<T>::add_front(T it)
{m_Mutex.Lock();if (datacache_queue.size() > QSize) {queue_overS++;datacache_queue.pop_front();}datacache_queue.push_front(it);m_Mutex.Unlock();if (queue_overS >= 10) {reportLogCacheOver(queue_desc.c_str(),QSize);queue_overS = 0;}
}template <class T>
void QueueData<T>::clear()
{m_Mutex.Lock();datacache_queue.clear();m_Mutex.Unlock();queue_overS = 0;
}

        spaceMgr.cpp

#include "spaceMgr.h"#include "pysleep.h"
#include "DiskSpace.h"DiskSpaceMgr::DiskSpaceMgr(char disk_, int fsl_, std::string dir_/*="log"*/, std::string ext_/*="log"*/): DiskStr(disk_),freeSizeLimit(fsl_)
{DelInfo del_(dir_,ext_);dirs.push_back(del_);
}DiskSpaceMgr::~DiskSpaceMgr(void)
{}int DiskSpaceMgr::Run()
{int i_totalSize = 0;int i_freeSize = 0;while (true){if (pyfree::getDiskFreeSpace(DiskStr, i_totalSize, i_freeSize) > 0){if (freeSizeLimit > i_freeSize){for(unsigned int i=0; i<dirs.size(); ++i){std::string ext = dirs.at(i).ext;pyfree::moveOldFile(dirs.at(i).dir, ext);}}}pysleep(10);}return 0;
}void DiskSpaceMgr::add(std::string dir_,std::string ext_)
{DelInfo del_(dir_,ext_);dirs.push_back(del_);
}

相关文章:

c/c++开发,无可避免的模板编程实践(篇八)

一、借用标准库模板构造自己的模板 通常&#xff0c;模板设计是遵循当对象的类型不影响类中函数的行为时就使用模板。这也就是为何标准库提供大部分的模板都是与容器、迭代器、适配器、通用算法等有关&#xff0c;因为这些主要是除了对象集合行为&#xff0c;如读写、增删、遍历…...

Leetcode13. 罗马数字转整数

一、题目描述&#xff1a; 罗马数字包含以下七种字符&#xff1a; I&#xff0c; V&#xff0c; X&#xff0c; L&#xff0c;C&#xff0c;D 和 M。 字符数字I1V5X10L50C100D500M1000 例如&#xff0c; 罗马数字 2 写做 II &#xff0c;即为两个并列的 1。12 写做 XII &…...

元宇宙对营销方式的影响

营销方式的变化通常伴随着技术的发展。我们已经看到营销方式从印刷媒体、电视、广播到互联网的转变。而现在&#xff0c;我们又处在下一个营销方式大跃进的风口浪尖上。关于元宇宙及其潜在的变革性影响&#xff0c;人们已经讨论了很多。虽然与元宇宙相关的大多数东西在很大程度…...

PERCCLI命令行程序说明

Dell EMC PowerEdge RAID控制器(PERC)命令行界面(CLI)实用程序用于管理RAID卡相关的配置和信息&#xff0c;命令的子命令和选项如下所示&#xff1a; help - lists all the commands with their usage. E.g. perccli help <command> help - gives details about a parti…...

系统架构——分布式架构负载均衡系统设计实战

摘要 关于“负载均衡”的解释&#xff0c;百度词条里&#xff1a;负载均衡&#xff0c;英文叫Load Balance&#xff0c;意思就是将请求或者数据分摊到多个操作单元上进行执行&#xff0c;共同完成工作任务。负载均衡&#xff08;Load Balance&#xff09;建立在现有网络结构之…...

机器学习算法: AdaBoost 详解

1. 集成学习概述 1.1. 定义 集成学习&#xff08;Ensemble learning&#xff09;就是将若干个弱分类器通过一定的策略组合之后产生一个强分类器。 弱分类器&#xff08;Weak Classifier&#xff09;指的就是那些分类准确率只比随机猜测略好一点的分类器&#xff0c;而强分类器&…...

6.824lab1总结

目录总体概要核心结构体coordinator思路&#xff1a;任务池管理RPC函数worker思路:实现细节总体概要 程序主要由mrcoordinator.go、mrworker.go为启动模块。 mrcoordinator.go: 启动rpc服务&#xff0c;循环等待m.Done()为true时退出。mrwoker.go:调用mr.worker(mapf, reduce…...

NIO蔚来 面试——IP地址你了解多少?

目录 前言 1、IP地址 1.1、什么是IP地址 1.2、IP地址的格式 1.2.1、32位二进制数表示IP地址&#xff0c;够用吗&#xff1f; 1.3、IP地址的组成 1.4、为什么会出现IPv6 1.4.1、为什么IPv6还没有大量普及呢&#xff1f; 1.5、子网掩码 1.6、特殊的IP地址 2、路由选择 …...

Gluten 首次开源技术沙龙成功举办,更多新能力值得期待

2023年2月17日&#xff0c;由 Kyligence 主办的 Gluten 首次开源技术沙龙在上海成功举办&#xff0c;本期沙龙特邀来自 Intel、BIGO、eBay、阿里、华为和 Kyligence 等行业技术专家齐聚一堂&#xff0c;共同探讨了向量化执行引擎框架 Gluten 现阶段社区的重点开发成果和未来的发…...

springboot+redis+lua实现限流

Redis 除了做缓存&#xff0c;还能干很多很多事情&#xff1a;分布式锁、限流、处理请求接口幂等性。。。太多太多了&#xff5e;今天想和小伙伴们聊聊用 Redis 处理接口限流。1. 准备工作首先我们创建一个 Spring Boot 工程&#xff0c;引入 Web 和 Redis 依赖&#xff0c;同时…...

线段树总结

文章目录参考文档题目线段树实现单点修改&#xff0c;区间求值模板题目308. 二维区域和检索 - 可变区间修改&#xff0c;区间求值1. 掉落的方块&#xff08;区间开点&#xff09;2. 维护序列3. 一个简单的问题24. 天际线问题动态开点1. 区间和个数(单点修改开点)问题以及注意事…...

龙芯GS232(MIPS 32)架构cache管理笔记

1 mips32架构 MIPS架构是一种基于精简指令集&#xff08;Reduced Instruction Set Computer&#xff0c;RISC&#xff09;的计算机处理器架构。MIPS架构由MIPS Technologies公司在1981年开发&#xff0c;并在1984年发布了第一款MIPS处理器。 MIPS架构的特点包括&#xff1a; …...

js去重

<script>let arr [{ id: 0, name: "张三" },{ id: 1, name: "李四" },{ id: 2, name: "王五" },{ id: 3, name: "赵六" },{ id: 1, name: "孙七" },{ id: 2, name: "周八" },{ id: 2, name: "吴九&qu…...

小白都能看懂的C语言入门教程

文章目录C语言入门教程1. 第一个C语言程序HelloWorld2. C语言的数据类型3. 常量变量的使用4. 自定义标识符#define5. 枚举的使用6. 字符串和转义字符7. 判断和循环8. 函数9. 数组的使用10. 操作符的使用11. 结构体12. 指针的简单使用C语言入门教程 1. 第一个C语言程序HelloWor…...

leetcode 21~30 学习经历

leetcode 21~30 学习经历21. 合并两个有序链表22. 括号生成23. 合并K个升序链表24. 两两交换链表中的节点25. K 个一组翻转链表26. 删除有序数组中的重复项27. 移除元素28. 找出字符串中第一个匹配项的下标29. 两数相除30. 串联所有单词的子串小结21. 合并两个有序链表 将两个升…...

让ArcMap变得更加强大,用python执行地理处理以及编写自定义脚本工具箱

文章目录一、用python执行地理处理工具1.1 例&#xff1a;乘以0.00011.2 例&#xff1a;裁剪栅格1.3 哪里查看调用某工具的代码&#xff1f;二、用python批量执行地理处理工具2.1 必需的python语法知识for循环语句缩进的使用注释的使用2.2 一个批处理栅格的代码模板三、创建自定…...

SAP 项目实施阶段全过程

在sap实施项目的周期和步骤上&#xff0c;根据各公司对业务的理解不同&#xff0c;也被划分为各个阶段&#xff0c;但其中由普华永道提出的分七步走&#xff0c;个人觉得对刚进入这一行业的人很有帮助&#xff0c;接下来一起分享和讨论下&#xff1a; sap实施项目生命周期&…...

idea中的Maven导包失败问题解决总结

idea中的Maven导包失败问题解决总结 先确定idea和Maven 的配置文件settings 没有问题 找到我们本地的maven仓库&#xff0c;默认的maven仓库路径是在\C:\Users\用户名.m2下 有两个文件夹&#xff0c;repositotry是放具体jar包的&#xff0c;根据报错包的名&#xff0c;找对应文…...

REDIS中的缓存穿透,缓存击穿,缓存雪崩原因以及解决方案

需求引入一般在项目的开发中,都是使用关系型数据库来进行数据的存储&#xff0c;通常不会存在什么高并发的情况&#xff0c;可是一旦涉及大数据量的需求&#xff0c;比如商品抢购&#xff0c;网页活动导致的主页访问量瞬间增大&#xff0c;单一使用关系型数据库来保存数据的系统…...

数据库及缓存之MySQL(一)

思维导图 常见知识点 1.mysql存储引擎&#xff1a; 2.innodb与myisam区别&#xff1a; 3.表设计字段选择&#xff1a; 4.mysql的varchar(M)最多存储数据&#xff1a; 5.事务基本特性&#xff1a; 6.事务并发引发问题&#xff1a; 7.mysql索引&#xff1a; 8.三星索引&#xf…...

项目管理中,项目经理需要具备哪些能力?

项目经理是团队的领导者&#xff0c;是带领项目团队对项目进行策划、执行&#xff0c;完成项目目标&#xff0c;对于项目经理来说&#xff0c;想要有序推进项目&#xff0c;使项目更成功&#xff0c;光有理论知识是不够的&#xff0c;也要具备这些能力&#xff1a; 1、分清主…...

itk中的一些图像处理

文章目录1.BinomialBlurImageFilter计算每个维度上的最近邻居平均值2.高斯平滑3.图像的高阶导数 RecursiveGaussianImageFilter4.均值滤波5.中值滤波6.离散高斯平滑7.曲率驱动流去噪图像 CurvatureFlowImageFilter8.由参数alpha和beta控制的幂律自适应直方图均衡化9.Canny 边缘…...

Endless lseek导致的SQL异常

最近碰到同事咨询的一个问题&#xff0c;在执行一个函数时&#xff0c;发现会一直卡在那里。 strace抓了下发现会话一直在执行lseek&#xff0c;大致情况如下&#xff1a; 16:13:55.451832 lseek(33, 0, SEEK_END) 1368064 <0.000037> 16:13:55.477216 lseek(33, 0, SE…...

JUC-day01

JUC-day01 什么是JUC线程的状态: wait sleep关键字:同步锁 原理(重点)Lock接口: ReentrantLock(可重入锁)—>AQS CAS线程之间的通讯 1 什么是JUC 1.1 JUC简介 在Java中&#xff0c;线程部分是一个重点&#xff0c;本篇文章说的JUC也是关于线程的。JUC就是java.util .con…...

Mind+Python+Mediapipe项目——AI健身之跳绳

原文&#xff1a;MindPythonMediapipe项目——AI健身之跳绳 - DF创客社区 - 分享创造的喜悦 【项目背景】跳绳是一个很好的健身项目&#xff0c;为了获知所跳个数&#xff0c;有的跳绳上会有计数器。但这也只能跳完这后看到&#xff0c;能不能在跳的过程中就能看到&#xff0c;…...

数据库概述

20世纪60年代后期&#xff0c;就出现了数据库技术。取得成就如下&#xff1a;造就了四位图灵奖得主发展成为以数据建模和DBMS核心技术为主&#xff0c;内容丰富的一门学科。带动了一个巨大的软件产业-DBMS产品及其相关工具和解决方案。四个基本概念数据数据是数据库中存储的基本…...

【已解决】解决IDEA的maven刷新依赖时出现Connot reconnect错误

前言 小编我将用CSDN记录软件开发求学之路上亲身所得与所学的心得与知识&#xff0c;有兴趣的小伙伴可以关注一下&#xff01;也许一个人独行&#xff0c;可以走的很快&#xff0c;但是一群人结伴而行&#xff0c;才能走的更远&#xff01;让我们在成长的道路上互相学习&#…...

动态链接库(.so)文件的变编译和引用、执行

动态链接库(.so)文件的变编译和引用 动态链接库&#xff1a;SO&#xff08;Shared Object&#xff09;是一种动态链接库&#xff0c;也被称为共享库。它是一种可被多个程序共享使用的二进制代码库&#xff0c;其中包含已编译的函数和代码。与静态链接库不同&#xff0c;动态链接…...

linux(centos8)文件解压命令

linux解压命令tar 解压命令常用解压命令1 [.tar] 文件 解压到当前文件夹2 [.tar.gz] 文件 解压到当前文件夹3 [.tar] 解压到指定文件夹 -C 必须是大写unzip 解压命令常用解压命令1 [.zip]解压到当前文件夹2 [.zip] 解压到指定文件夹2 [.zip] 解压到指定文件夹&#xff08;强行覆…...

阅读笔记6——通道混洗

一、逐点卷积 当前先进的轻量化网络大都使用深度可分离卷积或组卷积&#xff0c;以降低网络的计算量&#xff0c;但这两种操作都无法改变特征图的通道数&#xff0c;因此需要使用11的卷积。总体来说&#xff0c;逐点的11卷积有如下两点特性&#xff1a; 可以促进通道之间的信息…...