一个可自由添加so动态库的框架

有文件描述符的队列原型

#include <iostream>
#include <queue>
#include <mutex>
#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <thread>
#include <unistd.h>
#include <vector>
#include <optional>typedef struct {char strOutTime[24];char strModuleId[5];char strLevel[5];short iContentLength;    char strContent[4096];
} DataItem;class DataItemQueue {
private:std::queue<DataItem> queue_;std::mutex mtx_;int event_fd;public:DataItemQueue() : event_fd(eventfd(0, 0)) {}~DataItemQueue() { close(event_fd); }void push(DataItem value) {{std::lock_guard<std::mutex> lock(mtx_);queue_.push(value);}uint64_t signal = 1;write(event_fd, &signal, sizeof(signal));  // 通知 eventfd}std::optional<DataItem> pop() {uint64_t result;read(ready_fd, &result, sizeof(result));  // 清除 eventfd 信号std::lock_guard<std::mutex> lock(mtx_);if (queue_.empty()) return std::nullopt;DataItem value = queue_.front();queue_.pop();return value;}int get_event_fd() const { return event_fd; }
};void monitor_queues(std::vector<DataItemQueue*>& queues) {int epoll_fd = epoll_create1(0);// 注册每个队列的 event_fdfor (auto& queue : queues) {struct epoll_event event;event.events = EPOLLIN;event.data.fd = queue->get_event_fd();epoll_ctl(epoll_fd, EPOLL_CTL_ADD, queue->get_event_fd(), &event);}struct epoll_event events[10];while (true) {int nfds = epoll_wait(epoll_fd, events, 10, -1);for (int i = 0; i < nfds; ++i) {int ready_fd = events[i].data.fd;// 找到对应的队列并读取数据for (auto& queue : queues) {if (queue->get_event_fd() == ready_fd) {auto value = queue->pop();if (value) {std::cout << "iContentLength: " << value->iContentLength << std::endl;std::cout << "strContent: " << value->strContent << std::endl;std::cout << "strLevel: " << value->strLevel << std::endl;std::cout << "strModuleId: " << value->strModuleId << std::endl;std::cout << "strOutTime: " << value->strOutTime << std::endl;}}}}}close(epoll_fd);
}int main() {DataItemQueue queue1, queue2, queue3;std::vector<DataItemQueue*> queues = {&queue1, &queue2, &queue3};std::thread monitor_thread(monitor_queues, std::ref(queues));// 模拟向队列写入数据DataItem item1 = {"abcde", "fghi", "lmno", 1, "qrstu"};DataItem item2 = {"edcba", "ihgf", "onml", 2, "utsrq"};DataItem item3 = {"12345", "4321", "5678", 3, "78901"};queue1.push(item1);queue2.push(item2);queue3.push(item3);monitor_thread.join();return 0;
}

线程类原型

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>using FunctionPointer = void(*)(); class ControlledThread {
public:ControlledThread(FunctionPointer func) : workerFunction(func), ready(false), stop(false) {}void start() {worker = std::thread(&ControlledThread::threadFunction, this);}void triggerStart() {{std::lock_guard<std::mutex> lock(mtx);ready = true;}cv.notify_one();}void stopThread() {{std::lock_guard<std::mutex> lock(mtx);stop = true;ready = true;}cv.notify_one();if (worker.joinable()) {worker.join();}}private:std::thread worker;std::mutex mtx;std::condition_variable cv;FunctionPointer workerFunction;bool ready;bool stop;void threadFunction() {std::unique_lock<std::mutex> lock(mtx);cv.wait(lock, [this] { return ready; });if (stop) {return;}if (workerFunction) {workerFunction();}}
};void myFunction() {std::cout << "Executing myFunction in thread.\n";std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟任务执行std::cout << "myFunction finished executing.\n";
}int main() {// 创建 ControlledThread,并传入函数指针ControlledThread controlledThread(myFunction);controlledThread.start();  // 创建并启动线程,进入等待状态std::cout << "Main thread doing some work...\n";std::this_thread::sleep_for(std::chrono::seconds(1));  // 模拟主线程工作std::cout << "Triggering thread start.\n";controlledThread.triggerStart();  // 启动子线程controlledThread.stopThread();  // 等待子线程完成并清理return 0;
}

dlopen原型

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>// 结构体用于封装一个共享库的管理
typedef struct {void *handle;  // dlopen 返回的句柄const char *so_path;  // 共享库路径
} SharedLib;// 加载共享库并获取句柄
SharedLib *load_shared_lib(const char *so_path) {SharedLib *lib = (SharedLib *)malloc(sizeof(SharedLib));if (lib == NULL) {fprintf(stderr, "Failed to allocate memory for SharedLib\n");return NULL;}// 使用 RTLD_LAZY 模式加载共享库lib->handle = dlopen(so_path, RTLD_LAZY);if (!lib->handle) {fprintf(stderr, "Failed to load %s: %s\n", so_path, dlerror());free(lib);return NULL;}lib->so_path = so_path;return lib;
}// 获取函数符号
void *get_function(SharedLib *lib, const char *func_name) {// 清除上一个错误dlerror();void *func_ptr = dlsym(lib->handle, func_name);char *error = dlerror();if (error != NULL) {fprintf(stderr, "Failed to get symbol %s: %s\n", func_name, error);return NULL;}return func_ptr;
}// 关闭共享库
void close_shared_lib(SharedLib *lib) {if (lib->handle) {dlclose(lib->handle);lib->handle = NULL;}free(lib);
}// 示例:调用共享库中的函数
int main() {// 例如加载 "libm.so" 数学库const char *so_path = "/lib/x86_64-linux-gnu/libm.so.6";SharedLib *math_lib = load_shared_lib(so_path);if (math_lib == NULL) {return 1;}// 获取 sin 函数double (*sin_func)(double) = (double (*)(double))get_function(math_lib, "sin");if (sin_func == NULL) {close_shared_lib(math_lib);return 1;}// 调用 sin 函数double result = sin_func(3.14159 / 2);  // sin(π/2)printf("sin(π/2) = %f\n", result);// 关闭并释放共享库close_shared_lib(math_lib);return 0;
}

查找json文件和so文件配对的方法

// 扫描目录中的文件,按前缀存储指定扩展名文件的路径
void scan_directory(const std::string& directory, const std::string& extension, std::map<std::string, std::string>& files) {DIR* dir = opendir(directory.c_str());if (!dir) {std::cerr << "无法打开目录: " << directory << std::endl;return;}struct dirent* entry;while ((entry = readdir(dir)) != nullptr) {std::string filename = entry->d_name;// 检查是否为常规文件并匹配扩展名if (entry->d_type == DT_REG && filename.size() > extension.size() &&filename.substr(filename.size() - extension.size()) == extension) {// 提取文件前缀(去掉扩展名部分)std::string prefix = filename.substr(0, filename.size() - extension.size());files[prefix] = directory + "/" + filename;}}closedir(dir);
}// 查找目录1中的 .json 文件和目录2中的 .so 文件,匹配相同前缀
std::vector<Config> find_module_files(const std::string& dir1, const std::string& dir2) {std::map<std::string, std::string> json_files;std::map<std::string, std::string> so_files;// 扫描目录1中的 .json 文件scan_directory(dir1, ".json", json_files);// 扫描目录2中的 .so 文件scan_directory(dir2, ".so", so_files);// 查找相同前缀的文件名std::vector<Config> matched_files;for (const auto& json_file : json_files) {const std::string& prefix = json_file.first;std::string libprefix = "lib" + prefix;if (so_files.find(libprefix) != so_files.end()) {matched_files.push_back({prefix, json_file.second, so_files[libprefix]});}}return matched_files;
}std::vector<Config> configs = find_module_files(json_dir, so_dir);
for (const auto& config : configs) {std::cout << "Name: " << config.name << "\n";std::cout << "JSON file: " << config.json_path << "\n";std::cout << "SO file: " << config.so_path << "\n";
}

动态库接口原型

extern "C" int open(const char *pathname, int flags);
extern "C" int close(int fd);
extern "C" ssize_t read(int fd, void *buf, size_t count);
extern "C" ssize_t write(int fd, const void *buf, size_t count);
extern "C" int ioctl(int fd, unsigned long request, ...);int open(const char *pathname, int flags)
{if (handle != nullptr) {return 0;}handle = new HANDLE();handle->thread = new ControlledThread(thread);handle->thread->start();handle->queue = new DataItemQueue();return handle->queue->get_event_fd();
}int close(int fd)
{if (handle == nullptr) {return 0;}delete handle->thread;delete handle;handle = nullptr;return 0;
}ssize_t read(int fd, void *buf, size_t count)
{DataItem value = handle->queue->pop();// if (value) {std::cout << "iContentLength: " << value.iContentLength << std::endl;std::cout << "strContent: " << value.strContent << std::endl;std::cout << "strLevel: " << value.strLevel << std::endl;std::cout << "strModuleId: " << value.strModuleId << std::endl;std::cout << "strOutTime: " << value.strOutTime << std::endl;// }return 0;
}ssize_t write(int fd, const void *buf, size_t count)
{return 0;
}int ioctl(int fd, unsigned long request, ...)
{printf("module ioctl \n");va_list args;va_start(args, request);void* arg = va_arg(args, void*);char *str = (char *)arg;switch (request) {case THREAD_START:handle->thread->triggerStart();break;case THREAD_WAIT:handle->thread->stopThread();break;case CONFIG_NEELINK:if(str == NULL || access((const char *)str, R_OK) != 0) {LOG_E("Wrong parameter.");break;}if (SUCCESS != readConfigFile((const char *)str, &handle->param)) {LOG_E("thread configuration file read error.");freeParam(handle->param);break;}break;default:break;}va_end(args);return 0;
}

监控fd事件读取多个动态库队列

void monitor(std::vector<Config> configs) {const char *func_name[FUNC_NUM] = {"open", "close", "read", "write", "ioctl"};void *funcptr[MAX_SO_FILES_NUM][FUNC_NUM] = {0};SharedLib *shareLib[MAX_SO_FILES_NUM] = {0};int epoll_fd = epoll_create1(0);std::map<int32_t, size_t> mp;size_t module_cnt = configs.size();for(size_t i = 0; i < module_cnt; i++) {shareLib[i] = load_shared_lib(configs.at(i).so_path.c_str());if (shareLib[i] == NULL) {printf("load so: %s failed \n", configs.at(i).so_path.c_str());continue;}for(size_t j = 0; j < FUNC_NUM; j++) {funcptr[i][j] = get_function(shareLib[i], func_name[j]);if (funcptr[i][j] == NULL) {close_shared_lib(shareLib[i]);printf("get func: %s failed from: %s \n", func_name[j], configs.at(i).so_path.c_str());break;}}int fd = ((openptr)funcptr[i][OPEN])(configs.at(i).name.c_str(), 0);if (fd == -1) {perror("Failed to open");}printf("openptr fd = %d \n", fd);mp.insert(std::map<int32_t, size_t>::value_type(fd, i));struct epoll_event event;event.events = EPOLLIN;event.data.fd = fd;epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &event);int res = ((ioctlptr)funcptr[i][IOCTL])(fd, CONFIG_NEELINK, configs.at(i).json_path.c_str());if (res == -1) {perror("Failed to configure CONFIG_NEELINK");}printf("ioctlptr res = %d \n", res);res = ((ioctlptr)funcptr[i][IOCTL])(fd, THREAD_START);if (res == -1) {perror("Failed to configure THREAD_START");}printf("ioctlptr res = %d \n", res);}struct epoll_event events[10];while (true) {int nfds = epoll_wait(epoll_fd, events, 10, -1);for (int i = 0; i < nfds; ++i) {int ready_fd = events[i].data.fd;try {((readptr)funcptr[mp.at(ready_fd)][READ])(0, nullptr, 0);}catch(const std::exception& e){std::cerr << e.what() << '\n';}}}for(size_t i = 0; i < module_cnt; i++) {close_shared_lib(shareLib[i]);((closeptr)funcptr[i][CLOSE])(0);}
}static std::thread* thread = nullptr;
int run(std::string json_dir, std::string so_dir) {std::vector<Config> configs = find_module_files(json_dir, so_dir);for (const auto& config : configs) {std::cout << "Name: " << config.name << "\n";std::cout << "JSON file: " << config.json_path << "\n";std::cout << "SO file: " << config.so_path << "\n";}thread = new std::thread(monitor, configs);// thread->join();return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/60956.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据库】如何保证数据库迁移过程中数据的一致性?

在数据库迁移过程中&#xff0c;保证数据的一致性是非常重要的&#xff0c;尤其是在涉及到多个表、多个数据库或分布式系统的情况下。以下是一些确保数据一致性的最佳实践和方法&#xff1a; 1. 备份数据 在开始迁移之前&#xff0c;进行全面的数据备份是确保数据一致性的第…

Kubernetes 10 问,测测你对 k8s 的理解程度

Kubernetes 10 问 假设集群有 2 个 node 节点&#xff0c;其中一个有 pod&#xff0c;另一个则没有&#xff0c;那么新的 pod 会被调度到哪个节点上&#xff1f; 应用程序通过容器的形式运行&#xff0c;如果 OOM&#xff08;Out-of-Memory&#xff09;了&#xff0c;是容器重…

Spring:IoC/DI加载properties文件

Spring框架可以通过Spring的配置文件完成两个数据源druid和C3P0的配置&#xff08;Spring&#xff1a;IOC/DI配置管理第三方bean&#xff09;&#xff0c;但是其中包含了一些问题&#xff0c;我们来分析下: 这两个数据源中都使用到了一些固定的常量如数据库连接四要素&#xf…

时钟之CSS+JS版

写在前面 此版本绘制的时钟基于CSSJS模式。 优点操作简单&#xff0c;缺点当然是不够灵活。下一篇会基于HTML5的canvas标签&#xff0c;使用JS绘制。会更灵活&#xff0c;元素更加丰富。 HTML代码 <div class"box"><article class"clock"><…

云计算虚拟化-kvm创建虚拟机

作者介绍&#xff1a;简历上没有一个精通的运维工程师。希望大家多多关注作者&#xff0c;下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 虚拟化&#xff0c;简单来说就是把一台服务器/PC电脑&#xff0c;虚拟成多台独立的虚拟机&#xff0c;每台虚拟机之间相互隔…

<QNAP 453D QTS-5.x> 日志记录:在 Docker 中运行的 Flask 应用安装 自签名 SSL 证书 解决 Chrome 等浏览器证书安全

原因&#xff1a;Chrome 不信任 ssc 证书 使启用了 HTTPS&#xff0c;即使有使用 自签名证书 (self-signed certificate 非由可信的证书颁发机构 【CA&#xff0c;Certificate Authority】签发的&#xff09;。浏览器 Chrome 默认不信任自签名证书&#xff0c;也会报 NET::ERR_…

模板——实现泛型编程的有力武器

模板——实现泛型编程的有力武器 我们为什么需要模板&#xff1f;模板 前言&#xff1a;关于模板&#xff0c;相信大家都有所而闻&#xff0c;以下是我对C模板的个人看法&#xff0c;希望能够帮助到你们呀&#xff01; 我们为什么需要模板&#xff1f; 请到大家看这一段代码&a…

针对git、giteeVSCode连接的使用 || Live Share插件使用

1.下载git 链接 打开终端&#xff0c;桌面鼠标右键 2.配置密钥 登录gitee。 设置密钥 查看官方文档 跟着教程 复制最后的输出进行密钥添加 验证是否添加成功 3.创建&连接远程仓库 创建仓库 git终端进行配置 远程仓库克隆到本地 桌面终端clone,克隆他人|自己的仓库到本地…

OpenGL ES 文字渲染进阶--渲染中文字体

旧文 OpenGL ES 文字渲染方式有几种? 一文中分别介绍了 OpenGL 利用 Canvas 和 FreeType 绘制文字的方法。 无论采用哪种方式进行渲染,本质上原理都是纹理贴图:将带有文字的图像上传到纹理,然后进行贴图。 渲染中文字体 利用 Canvas 绘制中文字体和绘制其他字体在操作方式上…

c# 调用c++ 的dll 出现找不到函数入口点

今天在调用一个设备的dll文件时遇到了一点波折&#xff0c;因为多c 不熟悉&#xff0c;调用过程张出现了找不到函数入口点&#xff0c;一般我们使用c# 调用c 文件&#xff0c;还是比较简单。 [DllImport("AtnDll2.dll",CharSet CharSet.Ansi)]public static extern …

贴代码框架PasteForm特性介绍之markdown和richtext

简介 PasteForm是贴代码推出的 “新一代CRUD” &#xff0c;基于ABPvNext&#xff0c;目的是通过对Dto的特性的标注&#xff0c;从而实现管理端的统一UI&#xff0c;借助于配套的PasteBuilder代码生成器&#xff0c;你可以快速的为自己的项目构建后台管理端&#xff01;目前管…

【H3C华三 】VRRP与BFD、Track联动配置案例

原创 厦门微思网络 组网需求 如图1所示&#xff0c;区域A和区域B用户所在网络的出口处部署了两台汇聚层设备&#xff08;Device A和Device B&#xff09;。 现要求使用VRRP与BFD、Track联动功能&#xff0c;实现以下需求&#xff1a; • 在Device A和Device B上分别配置两个…

【ubuntu18.04】vm虚拟机复制粘贴键不能用-最后无奈换版本

我是ubuntu16版本的 之前费老大劲安装的vmware tools结果不能用 我又卸载掉&#xff0c;安装了open-vm-tools 首先删除VMware tools sudo vmware-uninstall-tools.pl sudo rm -rf /usr/lib/vmware-tools sudo apt-get autoremove open-vm-tools --purge再下载open-vm-tools s…

机器学习-37-对ML的思考之机器学习发展的三个阶段和驱动AI发展三驾马车的由来

文章目录 1 引言2 机器学习发展的三个阶段2.1 萌芽期(20世纪50年代)2.1.1 达特茅斯会议(人工智能诞生)2.1.2 机器学习名称的由来2.2 知识期(20世纪80年代)2.2.1 知识瓶颈问题2.2.2 机器学习顶级会议ICML2.2.3 Machine Learning创刊2.2.4 神经网络规则抽取2.3 算法期(20世纪90年…

【景观生态学实验】实验二 景观类型分类

实验目的 1.掌握ArcGIS软件的基本操作&#xff1a;通过课堂理论学习与实验课的实际动手操作&#xff0c;学习并熟练掌握如何利用ArcGIS软件对遥感影像进行一些较为基础的数据处理与分析工作&#xff0c;具体包括波段合成、图像镶嵌、图像裁剪与图像分类等&#xff1b; 2.熟悉…

GPT-5 要来了:抢先了解其创新突破

Microsoft 的工程师计划于 2024 年 11 月在 Azure 上部署 Orion (GPT-5)。虽然这一版本不会向公众开放&#xff0c;但其上线被视为人工智能领域的一个重要里程碑&#xff0c;并将产生深远的影响。 文章目录 GPT-5 真的要来了GPT-4 的局限性GPT-5 的创新突破与遗留挑战GPT-5 预期…

web与网络编程

使用HTTP协议访问Web 通过发送请求获取服务器资源的Web浏览器等&#xff0c;被成为客户端(client)。 Web使用一种名为HTTP(超文本传输协议)的协议作为规范&#xff0c;完成从客户端到服务器端等一系列运作流程。 可以说&#xff0c;Web时建立在HTTP协议上通信的。 网络基础T…

FromData格式提交接口时入参被转成JSON格式问题

本地上传文件后通过事件提交文件&#xff0c;一般先通过前端组件生成文本流&#xff0c;在通过接口提交文本流&#xff0c;提交文本流一般使用FormData的入参形式传入&#xff0c;接口请求头也默认"Content-Type": “multipart/form-data”&#xff0c;但是某些场景统…

Springboot 微信小程序定位后将坐标转换为百度地图坐标,在百度地图做逆地址解析

问题解析以及解决思路 业务:微信小程序定位后,将坐标转换为百度地图坐标,在百度地图做逆地址解析 问题:微信小程序的定位是拿的腾讯地图的经纬度,但是我们app端这边使用的百度地图,如果直接使用腾讯地图的经纬度再使用腾讯地图的逆地址解析需要腾讯和百度商业授权,为了减少授权…

Python爬虫----python爬虫基础

一、python爬虫基础-爬虫简介 1、现实生活中实际爬虫有哪些&#xff1f; 2、什么是网络爬虫&#xff1f; 3、什么是通用爬虫和聚焦爬虫&#xff1f; 4、为什么要用python写爬虫程序 5、环境和工具 二、python爬虫基础-http协议和chrome抓包工具 1、什么是http和https协议…