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

news2024/11/14 19:58:39

有文件描述符的队列原型

#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_fd
    for (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.coloradmin.cn/o/2240376.html

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

相关文章

使用Java绘制图片边框,解决微信小程序map组件中marker与label层级关系问题,label增加外边框后显示不能置与marker上面

今天上线的时候发现系统不同显示好像不一样&#xff0c;苹果手机打开的时候是正常的&#xff0c;但是一旦用安卓手机打开就会出现label不置顶的情况。尝试了很多种办法&#xff0c;也在官方查看了map相关的文档&#xff0c;发现并没有给label设置zIndex的属性&#xff0c;只看到…

【专题】计算机网络之网络层

1. 网络层的几个重要概念 1.1 网络层提供的两种服务 (1) 让网络负责可靠交付 计算机网络模仿电信网络&#xff0c;使用面向连接的通信方式。 通信之前先建立虚电路 VC (Virtual Circuit) (即连接)&#xff0c;以保证双方通信所需的一切网络资源。 如果再使用可靠传输的网络…

vTESTstudio系列15--vTESTstudio-Doors的需求和测试用例的管理

最近有朋友在咨询vTESTstudio中怎么去跟Doors里面的需求去做好管理这方面的问题&#xff0c;临时加两篇文章介绍一下,Lets Go!!! 目录 1.Doors的配置&#xff1a; 1.1 安装Doors AddIn for vTESTstudio&#xff1a; 1.2 更新XML脚本&#xff1a; 1.3 导出需求的Trace Item…

波动中的金钥匙:趋势震荡指标——源码公布,仅供学习

趋势与震荡&#xff0c;两者在市场运行中紧密相连&#xff0c;相互影响。趋势往往是震荡累积后的自然延伸&#xff0c;而震荡则常常是趋势形成与调整的前奏。在各类行情与不同时间周期中&#xff0c;当前的震荡不过是更大周期趋势中的一个组成部分&#xff1b;相应的&#xff0…

面试_ABtest原理简介

01 什么是ABtest ABtest来源于假设检验&#xff0c;现有两个随机均匀的有样本组A、B&#xff0c;对其中一个组A做出某种改动&#xff0c;实验结束后分析两组用户行为数据&#xff0c;通过显著性检验&#xff0c;判断这个改动对于我们所关注的核心指标是否有显著的影响&#xf…

‘nodemon‘ 不是内部或外部命令,也不是可运行的程序

解决方法&#xff1a;使用 npx 临时运行 nodemon 如果你不想全局安装 nodemon&#xff0c;你可以使用 npx&#xff08;npm 5.2 及以上版本自带&#xff09;来临时运行 nodemon&#xff1a; npx nodemon server.jsnodemon正常配置 要在开发过程中实现每次修改 Node.js 代码后…

计算机网络基础(3)_应用层自定义协议与序列化

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 计算机网络基础(3)_应用层自定义协议与序列化 收录于专栏【计算机网络】 本专栏旨在分享学习计算机网络的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&a…

E2E、CRC、Checksum、Rollingcounter

文章目录 前言1、E2E2、CRC3、Checksum4、Rollingcounter总结 前言 在专栏文章仿真CAN报文发送的CRC校验算法&#xff08;附CAPL代码&#xff09;和同星TSMaster中如何自定义E2E校验算法中分别给出了CRC算法和E2E校验实现&#xff0c;从中也明白了为什么在测试中需要去做这些仿…

嵌入式硬件杂谈(一)-推挽 开漏 高阻态 上拉电阻

引言&#xff1a;对于嵌入式硬件这个庞大的知识体系而言&#xff0c;太多离散的知识点很容易疏漏&#xff0c;因此对于这些容易忘记甚至不明白的知识点做成一个梳理&#xff0c;供大家参考以及学习&#xff0c;本文主要针对推挽、开漏、高阻态、上拉电阻这些知识点的学习。 目…

二叉树面试题(C 语言)

目录 1. 单值二叉树2. 相同的树3. 对称二叉树4. 二叉树的前序遍历5. 二叉树的中序遍历6. 二叉树的后序遍历7. 另一颗树的子树8. 通过前序遍历返回中序遍历 1. 单值二叉树 题目描述&#xff1a; 如果二叉树每个节点都具有相同的值&#xff0c;那么该二叉树就是单值二叉树。只有…

MFC中Excel的导入以及使用步骤

参考地址 在需要对EXCEL表进行操作的类中添加以下头文件&#xff1a;若出现大量错误将其放入stdafx.h中 #include "resource.h" // 主符号 #include "CWorkbook.h" //单个工作簿 #include "CRange.h" //区域类&#xff0c;对Excel大…

【C++】类中的“默认成员函数“--构造函数、析构函数、拷贝构造、赋值运算符重载

目录 "默认"成员函数 概念引入&#xff1a; 一、构造函数 问题引入&#xff1a; 1&#xff09;构造函数的概念 2&#xff09;构造函数实例 3&#xff09;构造函数的特性 4)关于默认生成的构造函数 (默认构造函数) 默认构造函数未完成初始化工作实例: 二…

LeetCode【0052】N皇后II

本文目录 1 中文题目2 求解方法&#xff1a;位运算回溯法2.1 方法思路2.2 Python代码2.3 复杂度分析 3 题目总结 1 中文题目 n 皇后问题 研究的是如何将 n 个皇后放置在 n n 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 给你一个整数 n &#xff0c;返回 n 皇后问…

C语言-详细讲解-P1009 [NOIP1998 普及组] 高精度阶乘之和

目录 1.题目要求 2.题目解读 3.代码实现 4.一些小细节 1.数组储存大整数方式 2.memset函数介绍 3.digit与sum的关系 1.题目要求 2.题目解读 这道题本质就是高精度乘法高精度加法的结合&#xff0c;我之前有出过 高精度算法-保姆级讲解 希望详细了解的小伙伴可以去…

浅谈:基于三维场景的视频融合方法

视频融合技术的出现可以追溯到 1996 年 , Paul Debevec等 提出了与视点相关的纹理混合方法 。 也就是说 &#xff0c; 现实的漫游效果不是从摄像机的角度来看 &#xff0c; 但其仍然存在很多困难 。基于三维场景的视频融合 &#xff0c; 因其直观等特效在视频监控等相关领域有着…

Qt_day10_程序打包(完结)

目录 1. 设置图标 2. Debug和Release版本 3. 动态链接库 4. 打包 5. 联系项目要求 Qt开发的程序最终都是要给用户使用的&#xff0c;用户的电脑上不可能装一个Qt的开发环境导入项目使用。因此项目项目开发完成后需要打包——制作成安装包&#xff0c;用户直接下载并安装即可使用…

路径规划——RRT-Connect算法

路径规划——RRT-Connect算法 算法原理 RRT-Connect算法是在RRT算法的基础上进行的扩展&#xff0c;引入了双树生长&#xff0c;分别以起点和目标点为树的根节点同时扩展随机树从而实现对状态空间的快速搜索。在此算法中以两棵随机树建立连接为路径规划成功的条件。并且&…

【项目开发 | 跨域认证】JSON Web Token(JWT)

未经许可,不得转载。 文章目录 JWT设计背景:跨域认证JWT 原理JWT 结构JWT 使用方式注意JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案,本文介绍它的原理、结构及用法。 JWT设计背景:跨域认证 互联网服务的用户认证流程是现代应用中的核心组成部分,通常的流程…

学习笔记——PLCT:milk-v duo(持续更新)

买板子 官方标配有可能是单板&#xff08;如下图&#xff09;无工具包&#xff0c;记得买之前问一下客服。

Kubernetes-ArgoCD篇-01-简介

1、什么是Argo CD Argo CD 是针对 Kubernetes 的声明式 GitOps 持续交付工具。 Argo CD官方文档地址&#xff1a;https://argo-cd.readthedocs.io Argo CD源码地址&#xff1a;https://github.com/argoproj/argo-cd 1.1 关于Argo Argo是一个开源的项目&#xff0c;主要是扩…