欢迎光临
我们一直在努力

【AI大模型接入SDK】ChatServer 启动与停止模块实现

头像

🎬 个人主页:艾莉丝努力练剑

❄专栏传送门:《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录》 《Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享》

⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平


🎬 艾莉丝的简介:

在这里插入图片描述


文章目录

  • 1 ~> ChatServer 启动与停止模块
    • 1.1 业务背景与前置条件
    • 1.2 头文件定义(类声明)
      • 1.2.1 类成员说明
    • 1.3 start () 服务启动接口实现
      • 1.3.1 核心逻辑流程
    • 1.4 stop () 服务停止接口实现
      • 1.4.1 核心逻辑流程
    • 1.5 isRunning () 状态查询接口实现
    • 1.6 ChatServer 构造函数关键初始化逻辑
  • 2 ~> 关键技术要点与坑点总结
    • 2.1 为什么必须放到子线程执行 listen
    • 2.2 为什么使用 std::atomic,不使用普通 bool
    • 2.3 detach 线程注意事项
    • 2.4 接口调用时序约束
  • 3 ~> 面试核心考点
  • 结尾

在这里插入图片描述


1 ~> ChatServer 启动与停止模块

基于 C++ + httplib 库实现 HTTP 聊天服务,解决服务启停、主线程阻塞、多线程并发状态安全问题

1.1 业务背景与前置条件

  • 前置工作:模型配置完成,聊天 SDK 完成初始化;基于httplib::Server构建 HTTP 服务实例
  • 需要实现 3 个核心接口:服务启动、服务停止、运行状态检测
  • 核心痛点:httplib::Server::listen()为阻塞调用,直接在主线程调用会阻塞整个程序,必须将服务监听放置在独立子线程执行
  • 并发风险:启停跨线程读写运行状态标记变量,普通 bool 会产生数据竞争,必须使用原子变量保证线程安全

1.2 头文件定义(类声明)

1.2.1 类成员说明

  • 构造函数:接收服务器配置结构体ServerConfig
  • 析构函数:资源回收
  • 对外成员函数
    • bool start():启动 HTTP 服务,子线程运行监听逻辑
    • void stop():停止 HTTP 服务
    • bool isRunning() const:获取服务当前运行状态
  • 私有成员
    • ServerConfig _config:保存传入的服务 IP、端口配置
    • std::unique_ptr<httplib::Server> _chatServer:httplib 服务智能指针对象
    • std::shared_ptr<ai_chat_sdk::ChatSDK> _chatSDK:聊天 SDK 智能指针
    • std::atomic<bool> _isRunning{false}:原子布尔标记,标记服务运行状态,解决多线程读写竞争

#pragma once
#include <memory>
#include <atomic>
#include <httplib.h>
#include "server_config.h"
#include "ai_chat_sdk.h"

struct ServerConfig
{
std::string host;
uint16_t port;
};

namespace ai_chat_server
{
class ChatServer
{
public:
ChatServer(const ServerConfig& config);
~ChatServer();

bool start(); // 启动服务器
void stop(); // 停止服务器
bool isRunning() const; // 获取运行状态

private:
ServerConfig _config;
std::unique_ptr<httplib::Server> _chatServer = nullptr;
std::shared_ptr<ai_chat_sdk::ChatSDK> _chatSDK = nullptr;
std::atomic<bool> _isRunning{false}; // 原子变量,多线程安全标记运行状态
};
}

1.3 start () 服务启动接口实现

1.3.1 核心逻辑流程

  • 使用_isRunning.load()原子读操作,检测服务是否已经运行;若正在运行打印错误日志直接返回 false
  • 创建std::thread子线程,lambda 捕获 this 指针,线程内部执行httplib::Server::listen()阻塞监听
  • 调用detach()分离线程,子线程独立运行,与主线程解耦,主线程不会被 listen 阻塞
  • 使用_isRunning.store(true)原子写,标记服务已启动
  • 打印启动日志,返回 true 代表启动调用成功
  • 注意:detach()只是分离线程,不代表 listen 监听一定成功;detach 之后主线程无法 join 回收该线程资源。listen 内部会处理端口绑定失败,错误日志会在子线程输出。

    #include "ChatServer.h"
    #include <thread>
    #include "logger.h"

    namespace ai_chat_server
    {
    bool ChatServer::start()
    {
    // 原子加载:检测服务是否已经处于运行状态
    if (_isRunning.load())
    {
    ERR("ChatServer is running!!!");
    return false;
    }

    // 创建子线程,将阻塞的listen监听放到子线程执行,避免阻塞主线程
    std::thread serverThread([this]() -> void
    {
    // httplib阻塞监听,绑定配置中的IP与端口
    _chatServer->listen(_config.host, _config.port);
    INFO("ChatServer start on {}:{}", _config.host, _config.port);
    });

    // 线程分离,子线程独立运行生命周期,主线程不再管理该线程
    serverThread.detach();

    // 原子写:标记服务已经启动
    _isRunning.store(true);
    INFO("ChatServer start success!!!");
    return true;
    }
    }

    1.4 stop () 服务停止接口实现

    1.4.1 核心逻辑流程

  • _isRunning.load()读取原子状态,如果服务未运行,打印错误日志直接返回
  • 校验_chatServer指针有效性,调用httplib::Server::stop()终止 HTTP 监听
  • _isRunning.store(false)原子写,标记服务停止
  • 输出停止日志
  • 底层原理:httplib::Server::stop()会主动终止 listen 阻塞调用,退出子线程内部的监听循环;detach 分离后的子线程执行完 listen 退出后自动回收。

    namespace ai_chat_server
    {
    void ChatServer::stop()
    {
    // 原子加载读取运行状态
    if (!_isRunning.load())
    {
    ERR("ChatServer is not running!!!");
    return;
    }

    // 调用httplib库接口停止服务
    if (_chatServer)
    {
    _chatServer->stop();
    }

    // 原子写,更新运行标记为停止
    _isRunning.store(false);
    INFO("ChatServer stop success!!!");
    }
    }

    1.5 isRunning () 状态查询接口实现

    • 直接调用load()原子读操作返回内部状态,const 修饰保证不修改对象

    namespace ai_chat_server
    {
    bool ChatServer::isRunning() const
    {
    return _isRunning.load();
    }
    }

    1.6 ChatServer 构造函数关键初始化逻辑

    namespace ai_chat_server
    {
    ChatServer::ChatServer(const ServerConfig& config):_config(config)
    {
    // 创建httplib服务实例
    _chatServer = std::make_unique<httplib::Server>();
    if (!_chatServer)
    {
    ERR("ChatServer init Failed!!!");
    return;
    }
    // 此处完成ChatSDK初始化逻辑
    }
    }


    2 ~> 关键技术要点与坑点总结

    2.1 为什么必须放到子线程执行 listen

    • httplib::Server::listen()是同步阻塞 API,调用后函数不会返回,直到调用 stop ()、发生异常出错
    • 如果直接在主线程调用 listen,主线程被挂起,程序无法执行其他业务逻辑,无法调用 stop 完成关闭

    2.2 为什么使用 std::atomic,不使用普通 bool

    • start 在主线程修改_isRunning,子线程库内部也会间接访问,stop 也会修改;多线程同时读写普通 bool 变量会触发数据竞争,属于 C++ 未定义行为
    • std::atomic<bool>提供原子读写:
      • .load():原子读,获取变量值
      • .store(val):原子写,写入变量值
    • 禁止直接对原子变量使用=赋值,规范使用 load/store 接口

    2.3 detach 线程注意事项

    • detach()之后主线程不能 join 该线程,子线程运行结束后操作系统自动回收资源
    • 风险点:对象提前析构,如果 ChatServer 对象被销毁,而子线程还在执行 lambda 内部逻辑,会发生野指针访问崩溃;业务层要保证对象生命周期大于服务子线程生命周期。

    2.4 接口调用时序约束

  • 先构造 ChatServer 对象,完成内部_chatServer初始化
  • 调用start()启动服务
  • 可调用isRunning()查询状态
  • 退出前调用stop()停止服务,再销毁 ChatServer 对象

  • 3 ~> 面试核心考点

  • httplib listen 阻塞特性,如何解决主线程阻塞问题
  • 多线程共享状态变量为什么要使用 atomic,数据竞争概念
  • std::thread detach 的作用、优缺点、潜在风险
  • start/stop/isRunning 整套接口的线程安全设计思路
  • httplib::stop 底层行为,stop 调用后 listen 如何退出阻塞

  • 结尾

    uu们,本文的内容到这里就全部结束了,艾莉丝在这里再次感谢您的阅读!

    艾莉丝努力练剑

    C/C++ & Linux 底层探索者 | 一个正在努力练剑的技术博主


    👀
    【关注】 跟随我一起深耕技术领域,见证每一次成长。

    ❤️
    【点赞】 让优质内容被更多人看见,让知识传递更有力量。

    ⭐
    【收藏】 把核心知识点存好,在需要时随时查、随时用。

    💬
    【评论】 分享你的经验或疑问,评论区一起交流避坑!

    不要忘记给博主“一键四连”哦!

    “今日练剑达成!”

    “技术之路难免有困惑,但同行的人会让前进更有方向。”

    结语:希望对学习Linux相关内容的uu有所帮助,不要忘记给博主“一键四连”哦!

    往期回顾:

    【AI大模型接入SDK】ChatServer HTTP接口模块实现总览

    🗡博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!🗡

    ૮₍ ˶ ˊ ᴥ ˋ˶₎ა

    在这里插入图片描述

    赞(0)
    未经允许不得转载:171主机测评 » 【AI大模型接入SDK】ChatServer 启动与停止模块实现
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址