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

子进程入口模板框架

下面把三种“灵活进程入口”方案掰开揉碎讲一遍,让你一眼看出:

  • 代码长啥样

  • 谁最简洁、谁最类型安全、谁最易扩展

  • 什么时候该用谁

方案 1:裸指针 + 固定签名(“C Style”)

// 入口固定死
using TaskFunc = void(*)(void* arg);void worker_main(void* raw)           // 子进程入口
{int fd = *(int*)raw;              // 先强转再解引用handle_client(fd);
}// 父进程
int client_fd = accept(listenfd, ...);
pid_t pid = fork();
if (pid == 0) {                       // 子进程worker_main(&client_fd);          // 直接调exit(0);
}

特点
✅ 最直观,无依赖,C/C++ 都能用
❌ 零类型检查,void* 一传错直接 UB
❌ 参数一多就完蛋,得封装结构体 + 二次强转

适用

  • 极底层、boot-strap 阶段

  • 与 C API 交互(pthread_create 之类)

方案 2:面向对象 + 统一基类(“OO Style”)

struct TaskBase {                      // 统一接口virtual ~TaskBase() = default;virtual void run() = 0;
};struct ClientTask : TaskBase {int fd;explicit ClientTask(int f) : fd(f) {}void run() override { handle_client(fd); }
};// 子进程入口永远只有这一句
void worker_main(TaskBase* task) {task->run();delete task;
}// 父进程
int client_fd = accept(listenfd, ...);
TaskBase* job = new ClientTask(client_fd);
pid_t pid = fork();
if (pid == 0) { worker_main(job); exit(0); }

特点
✅ 类型安全,编译器帮你检查
✅ 加新任务只需写新派生类,入口函数不动(开闭原则)
❌ 一次虚函数调用 + 一次 new/delete,有极小额外开销

适用

  • 业务逻辑经常扩展

  • 团队里 C++ 比重高,怕 void* 埋雷

方案 3:模板 + 泛型回调(“Modern C++ Style”)

template <typename F>
void worker_main(F f) {              // 编译期生成专属入口f();                             // 直接调 lambda
}// 父进程
int client_fd = accept(listenfd, ...);
auto job = [fd = client_fd]() { handle_client(fd); };
pid_t pid = fork();
if (pid == 0) { worker_main(std::move(job)); exit(0); }

特点
✅ 零虚函数、零动态分配,效率 = 手写函数
✅ 捕获列表想带几个参数就带几个,类型自动推导
❌ 每个 lambda 都会产生一份新二进制入口,体积略增
❌ 必须 C++14 及以上,纯 C 场景玩不了

适用

  • 性能敏感(高频 fork 短任务)

  • 喜欢“头文件里就搞定”的轻量级风格

重点讲解一下第三种方法

🌟 整体设计思路

想象你要开两家店:

  • 一家是"日志记录店"(CreatelogServer
  • 一家是"客户端服务店"(CreateClientServer

你作为老板(main函数)不能亲力亲为,所以你要:

  1. 招两个店长(CProcess对象)
  2. 给每个店长明确任务(SetEntryFunction
  3. 让店长自己去开店(CreateSubProcess
  4. 你继续做老板的其他事(main函数继续执行)

🔍 代码逐层拆解

1️⃣ 第一层:通用任务接口(CFunctionBase

class CFunctionBase {
public:virtual ~CFunctionBase(){}virtual int operator()() = 0; // 纯虚函数
};

👉 这是一个"任务合同模板"。规定所有任务必须:

  • 可以像函数一样被调用(operator()
  • 有标准的结束方式(虚析构函数)
  • 关键点 = 0 表示"这只是合同,具体内容由子类填写"

也是为了防止子类污染;

2️⃣ 第二层:具体任务包装(CFunction 模板类)

template<typename FUNC, typename... ARGS>
class CFunction : public CFunctionBase { // 必须继承基类!
private:std::function<int()> m_task; // 用标准库封装public:CFunction(FUNC func, ARGS... args) {// 用bind把函数和参数打包成可调用对象m_task = std::bind(func, args...);}int operator()() override {return m_task(); // 执行打包好的任务}
};

👉 这是一个"任务包装盒",可以:

  • 装入任意函数(比如 CreatelogServer
  • 带上任意参数(比如 &proclog
  • 封装成标准格式(符合 CFunctionBase 合同)

3️⃣ 第三层:进程管家(CProcess 类)

class CProcess {
private:CFunctionBase* m_func; // 指向任务的指针,必须用基类,子类会被污染pid_t m_pid;           // 进程IDpublic:// 设置任务template<typename FUNC, typename... ARGS>int SetEntryFunction(FUNC func, ARGS... args) {m_func = new CFunction<FUNC, ARGS...>(func, args...);return 0;}// 创建子进程int CreateSubProcess() {pid_t pid = fork(); // 关键!创建子进程if (pid == 0) {// 子进程:执行任务return (*m_func)();}// 父进程:记录子进程IDm_pid = pid;return 0;}
};

👉 这是"店长角色",负责:

  1. 接收任务SetEntryFunction 把函数打包成标准任务
  2. 分身术fork() 创建子进程(一分为二,两个相同进程)
  3. 分工
    • 子进程:执行任务((*m_func)()
    • 父进程:记住子进程ID(方便后续管理)

💡 关键知识点fork() 调用一次,返回两次:

  • 父进程得到子进程ID(>0)
  • 子进程得到0
  • 这就是代码中 if (pid == 0) 判断的原理

4️⃣ 第四层:具体业务(两个服务器函数)

int CreatelogServer(CProcess* proc) {// 实际应该写日志服务代码return 0;
}int CreateClientServer(CProcess* proc) {// 实际应该写客户端服务代码return 0;
}

👉 这是两个"分店的具体业务手册":

  • CreatelogServer:专做日志记录
  • CreateClientServer:专处理客户端请求
  • 参数 CProcess* proc 理论上可以用于进程控制(但示例中未使用)

⚠️ 注意:这两个函数在示例中是空的(返回0),实际项目中会填充具体逻辑。


5️⃣ 最终组装(main 函数)

int main() {// 1. 创建两个"店长"CProcess proclog, procclients;// 2. 分配任务proclog.SetEntryFunction(CreatelogServer, &proclog);procclients.SetEntryFunction(CreateClientServer, &procclients);// 3. 让店长去开店(创建子进程)proclog.CreateSubProcess();procclients.CreateSubProcess();// 4. 老板继续自己的事...return 0;
}

执行流程

  1. 创建两个 CProcess 对象(两个店长)
  2. 为每个店长分配任务:
    • proclog 负责运行 CreatelogServer
    • procclients 负责运行 CreateClientServer
  3. 调用 CreateSubProcess() 时发生"分身":
    • 第一次 fork:创建日志服务子进程
    • 第二次 fork:创建客户端服务子进程
  4. 最终系统中有3个进程
    • 1个父进程(main函数,很快结束)
    • 2个子进程(分别运行两个服务器)

http://www.dtcms.com/a/619183.html

相关文章:

  • wordpress分类目录文章排序优化
  • C++ Lambda 表达式实战入门与进阶
  • 网页设计和网站开发的区别怎么自己做游戏
  • Origin复现Nature级别的堆积柱状图
  • 【Unity基础】
  • 做网站小程序在哪点拉客户鹤壁网站推广公司
  • 工业互联网与智能制造的未来:人工智能与5G技术的完美融合
  • 5G与AI:推动智能制造的双引擎
  • 关于教做鞋的网站最新wordpress新建首页
  • 南通e站网站建设湛江网站建设哪家好
  • 基于VOCs灵敏度分析数据集的机器学习模型构建与实践
  • Odoo 19 制造与会计集成深度解析
  • 建筑网站步骤永兴集团网站
  • 验证码识别
  • 34线城市做网站推广菏泽做公司简介网站
  • 禁用 idea 屏幕阅读器功能 idea support screen readers
  • 营销型网站的案例wordpress培训类网站
  • 交通门户网站建设企业展厅设计比较好的公司
  • 长春网站建设哪家好网站页面设计培训
  • 网站商城微信支付接口博罗做网站报价
  • 招个网站建设维护通城网站建设
  • 机器学习:基于大数据二手房房价预测与分析系统 可视化 线性回归预测算法 Django框架 链家网站 二手房 计算机毕业设计✅
  • 广东网站制作公司排名海外推广引流
  • 资源网站快速优化排名视频 播放网站怎么做
  • 怎样建设学校网站首页怎么更新网站备案资料
  • 全国建设项目验收信息网站猪八戒 网站开发支付
  • FFmpeg解码流程核心要点
  • Numpy在OpenCV中的应用
  • 网站备案类型wordpress文档编辑
  • 网站建设的维护范围合肥网站建设yjhlw