)
使用 WSL 的 ProcessExitHandler 委托监控容器进程退出事件C API 指南【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL导读ProcessExitHandler是 WSLWindows Subsystem for LinuxC API 中用于接收容器进程退出通知的委托类型。通过Process::Exited事件注册该委托你的宿主应用可以在 WSL 容器内的进程退出时拿到退出码exitCode从而驱动等待逻辑、资源清理或状态同步。本文将带你掌握ProcessExitHandler的签名、订阅/退订方式、底层事件触发机制事件模式与流/丢弃模式的差异并结合仓库源码与端到端示例给出可直接落地的 C 实战方案。委托签名与触发条件在Microsoft.WSL.Containers命名空间中ProcessExitHandler被声明为一个携带单个int32_t参数的委托delegate void ProcessExitHandler(Int32 exitCode);其定义位于 wslcsdk.idl并作为Process运行时类的Exited事件类型对外暴露event ProcessExitHandler Exited;官方文档给出的最小订阅用法如下process.Exited([](int32_t exitCode) { printf(exit code: %d\n, exitCode); });要点exitCode为进程退出码int32_t可直接用于判断成功/失败0 表示成功。委托按事件触发时机分两条路径详见下文「两种触发路径」事件模式下由 SDK 的退出回调同步唤醒流/丢弃模式下由Exited事件在等待进程退出事件返回后触发。与ProcessCrashHandler进程崩溃通知不同ProcessExitHandler覆盖的是正常退出与信号终止等一般退出场景。订阅与退订基于 winrt 事件令牌Process::Exited是标准 winrt 事件订阅返回winrt::event_token退订时传入同一令牌。对应实现见 Process.cppwinrt::event_token Process::Exited(winrt::Microsoft::WSL::Containers::ProcessExitHandler const handler) { return m_exitedEvent.add(handler); } void Process::Exited(winrt::event_token const token) noexcept { m_exitedEvent.remove(token); }实战建议在调用Start()或container.Start()之前完成订阅避免错过进程快速退出时的通知窗口进程退出后若需解绑保存订阅返回的令牌并在合适时机调用process.Exited(token)退订通过Process::Close()或析构释放Process对象时内部会取消等待操作Process.cpp残留订阅不会造成悬垂回调。两种触发路径事件模式与流/丢弃模式ProcessExitHandler的触发路径取决于ProcessSettings::OutputMode()源码 Process.cpp 对此有明确分支事件模式ProcessOutputMode::EventApplyCallbacksToSettings()会把ExitCallback写入底层WslcProcessCallbacks结构并随设置下发StartWaitingForExitAsync()直接co_return不再额外等待。退出回调由 ExitCallback 触发m_exitedEvent(exitCode)void CALLBACK Process::ExitCallback(INT32 exitCode, _In_opt_ PVOID context) noexcept { auto process static_castProcess*(context); process-m_exitedEvent(exitCode); }流/丢弃模式ProcessOutputMode::Stream或DiscardApplyCallbacksToSettings()直接返回StartWaitingForExitAsync()调用WslcGetProcessExitEvent取得进程退出事件句柄通过co_await winrt::resume_on_signal(exitEventHandle.get())等待随后再触发m_exitedEvent(ExitCode())Process.cpp。该等待动作支持取消传播Close()时会取消m_waitForExitAction。在底层ExitCallback的触发由 IOCallback.cpp 的 IO 回调线程完成SDK 为 stdout/stderr 注册读句柄为退出注册EventHandle当进程退出且设置了onExit时从process-GetState读取状态与退出码并保证「即使取退出码失败也照常回调exitCode 置为 -1并告知调用方不会再收到 IO 回调」。这也解释了WslcProcessCallbacks结构体中的注释——使用 IO 回调时必须同时使用退出回调以规避「进程退出与 IO 缓冲区刷新之间的竞态」wslcsdk.h。与输出事件的搭配使用容器 init 进程通常需要「边读输出、边等退出」。事件模式下三个事件可以协同工作ProcessSettings eventSettings; eventSettings.OutputMode(ProcessOutputMode::Event); // ... 设置 CommandLine ... auto eventProc container.CreateProcess(eventSettings); eventProc.OutputReceived([](auto const data) { printf(stdout bytes: %zu\n, data.size()); }); eventProc.ErrorReceived([](auto const data) { printf(stderr bytes: %zu\n, data.size()); }); eventProc.Exited([](int32_t exitCode) { printf(done: %d\n, exitCode); }); eventProc.Start();其中OutputReceived/ErrorReceived的ProcessOutputHandler收到的是原始字节winrt::array_viewconst uint8_t可自行拼装为字符串详见 processoutputhandler.md。注意事件模式要求在使用前订阅OutputReceived/ErrorReceived否则抛hresult_illegal_method_call而Exited事件本身在两种输出模式下均可订阅Process.cpp。端到端实战等待 init 进程退出并读取退出码结合 end-to-end-example.md一个完整的「创建会话 → 拉镜像 → 配置 init 进程 → 启动容器 → 等待 init 退出 → 输出退出码 → 清理」流程如下#include winrt/Microsoft.WSL.Containers.h #include winrt/Windows.Foundation.h #include winrt/Windows.Foundation.Collections.h using namespace winrt; using namespace winrt::Microsoft::WSL::Containers; using namespace winrt::Windows::Foundation; using namespace winrt::Windows::Foundation::Collections; using namespace std::chrono_literals; int main() { init_apartment(); // 0. 检查 WSL 组件是否就绪 auto missing WslcService::GetMissingComponents(); if (missing ! static_castComponent(0)) { printf(WSL components are missing. Run: wsl --install\n); return 1; } // 1. 创建会话4 CPU、4 GB 内存 SessionSettings sessionSettings{ LMyApp, LC:\\WslcData }; sessionSettings.CpuCount(4); sessionSettings.MemorySizeInMB(4096); Session session{ sessionSettings }; session.Start(); // 2. 拉取镜像 PullImageOptions pullOpts{ Ldocker.io/library/alpine:latest }; co_await session.PullImageAsync(pullOpts); // 3. 配置 init 进程 ProcessSettings initProcSettings; initProcSettings.OutputMode(ProcessOutputMode::Event); auto argv single_threaded_vectorhstring(); argv.Append(L/bin/echo); argv.Append(LHello from WSL Container!); initProcSettings.CommandLine(argv); // 4. 创建容器 ContainerSettings containerSettings{ Lalpine:latest }; containerSettings.Name(Lhello-container); containerSettings.InitProcess(initProcSettings); auto container session.CreateContainer(containerSettings); // 5. 启动容器前先订阅 init 进程的 Exited 事件 auto initProcess container.InitProcess(); auto exitedEvent handle{ CreateEvent(nullptr, TRUE, FALSE, nullptr) }; int32_t initExitCode -1; initProcess.OutputReceived([](auto const data) { std::string text(data.begin(), data.end()); printf(%s, text.c_str()); }); initProcess.Exited( { initExitCode exitCode; SetEvent(exitedEvent.get()); }); // 6. 启动容器init 进程随之启动 container.Start(); // 7. 等待 init 进程退出30 秒超时 WaitForSingleObject(exitedEvent.get(), 30000); printf(Process exited with code: %d\n, initExitCode); // 8. 清理 if (container.State() ContainerState::Running) { container.Stop(Signal::SIGTERM, 10s); } container.Delete(DeleteContainerOption::None); session.Terminate(); return 0; }这段示例揭示了ProcessExitHandler的典型工程用法在跨线程的等待场景中委托回调内设置 Win32 事件SetEvent主线程用WaitForSingleObject阻塞等待从而把 SDK 回调线程与调用方线程安全地衔接起来Process::ExitCode()则用于在需要时主动查询退出码对应 Process.cpp 中的WslcGetProcessExitCode调用。相关参考委托与事件总览delegates-and-events/index.mdProcess类完整方法与事件说明process.md其中明确Exited在事件模式下由退出回调触发在流/丢弃模式下由等待进程退出事件触发崩溃通知委托processcrashhandler.md输出字节委托processoutputhandler.md底层 C 接口WslcProcessCallbacks与WslcSetProcessSettingsCallbackswslcsdk.hWinRT 包装实现Process.cppIO 回调线程实现IOCallback.cppWinRT 类型声明wslcsdk.idl【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考