You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

销毁含windows::stream_handle与命名管道的io_context时Boost.Asio触发访问违规

问题描述

在Windows环境下运行一个命名管道服务器服务,使用Boost.Asio在单线程通过C++20协程处理多客户端重叠IO,异步监听新客户端连接。服务关闭时通过设置Windows事件对象,由协程异步等待该事件,触发后调用io_context.stop()实现线程优雅退出。目前客户端连接、通信、断开逻辑均正常,但关机时会触发访问违规——即使无客户端连接,问题已定位到等待连接的协程。stop信号接收后,io_context.stop()调用成功,run()返回且线程正常退出并join,但销毁io_context时清理服务对象出错(调用无效函数指针func_),怀疑存在生命周期问题,但无法明确具体原因。

最小复现代码
#include <iostream>
#include <string>
#include <conio.h>
#include <boost/asio.hpp>
#include <boost/asio/windows/object_handle.hpp>

namespace as = boost::asio;

const char* pipeName = R"(//./pipe/asio-pipe)";

class DuplexPipe
{
public:
    DuplexPipe(as::io_context& ioctx, std::string pipeName)
        :
        stream_{ ioctx }
    {
        const auto pipeHandle = CreateNamedPipeA(
            pipeName.c_str(),
            PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // open mode
            PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, // pipe mode
            3,          // max instances
            4096,       // out buffer
            4096,       // in buffer
            0,          // timeout
            nullptr);   // security
        stream_.assign(pipeHandle);
    }
    as::awaitable<void> Accept()
    {
        as::windows::object_handle connEvt{ co_await as::this_coro::executor,
            CreateEventA(nullptr, TRUE, FALSE, nullptr) };
        OVERLAPPED over{ .hEvent = connEvt.native_handle() };
        ConnectNamedPipe(stream_.native_handle(), &over);
        if (const auto error = GetLastError(); error == ERROR_IO_PENDING) {
            // not yet connected, await on connection event
            co_await connEvt.async_wait(as::use_awaitable);
        }
        else if (error == ERROR_PIPE_CONNECTED) {
            // connected even before we could await event
        }
        else {
            // some error has occurred during connection
            std::cout << "Failed to connect" << std::endl;
            std::terminate();
        }
    }
private:
    as::windows::stream_handle stream_;
};

class PipeServer
{
public:
    PipeServer()
        :
        stopEvent_{ ioctx_, CreateEventA(nullptr, TRUE, FALSE, nullptr) }
    {
        thread_ = std::jthread{ [this] {
            as::co_spawn(ioctx_, [this]() -> as::awaitable<void> {
                co_await stopEvent_.async_wait(as::use_awaitable);
                ioctx_.stop();
            }, as::detached);
            as::co_spawn(ioctx_, Accept_(), as::detached);
            ioctx_.run();
        } };
    }
    void SignalStop()
    {
        SetEvent(stopEvent_.native_handle());
    }
private:
    as::awaitable<void> Accept_()
    {
        DuplexPipe pipe{ ioctx_, pipeName };
        co_await pipe.Accept();
        // at this point in the actual app we would spawn another Accept_ coro and then
        // proceed to communicate with the connected client
    }
    as::io_context ioctx_;
    as::windows::object_handle stopEvent_;
    std::jthread thread_;
};

int main(int argc, const char** argv)
{
    PipeServer srv;
    while (!_kbhit());
    srv.SignalStop();

    return 0;
}
问题分析与修复方案

核心问题

io_context.stop()仅会停止调度新的异步任务,但不会主动取消已提交的挂起异步操作。当服务停止时,Accept_协程处于挂起状态(等待客户端连接),其关联的DuplexPipe对象、connEvt事件对象及ConnectNamedPipe发起的重叠IO操作仍持有io_context的内部状态引用。当io_context被销毁时,这些挂起操作的回调尝试访问已释放的内存,最终触发访问违规。

修复步骤

  1. 添加资源清理逻辑
    给DuplexPipe添加析构函数,主动取消挂起的IO操作并关闭管道句柄:

    ~DuplexPipe()
    {
        if (stream_.is_open())
        {
            // 取消管道上挂起的所有IO操作
            CancelIoEx(stream_.native_handle(), nullptr);
            stream_.close();
        }
    }
    
  2. 优化停止流程
    修改停止事件的协程逻辑,确保在调用io_context.stop()前,清理所有挂起的工作项:

    as::co_spawn(ioctx_, [this]() -> as::awaitable<void> {
        co_await stopEvent_.async_wait(as::use_awaitable);
        // 通知执行器所有工作已完成,避免残留异步任务
        while (ioctx_.run_one());
        ioctx_.stop();
    }, as::detached);
    
  3. 改用Asio原生异步操作(可选)
    替换手动调用Windows API的逻辑,使用Boost.Asio封装的异步操作,让Asio自动管理重叠IO的生命周期,减少手动资源管理的风险。

内容的提问来源于stack exchange,提问作者chili

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 02:17:14