Day5 【补充】线程模型与异步处理

1. 核心思想与技术框架

1.1 核心设计思想

Fast-DDS的线程模型遵循专用线程+事件驱动的设计哲学:

  1. 线程职责单一化:每个线程负责特定任务(定时事件、网络I/O、异步发送等)
  2. 无共享状态优先:通过消息传递和队列解耦线程间通信
  3. 实时性保证:支持严格实时模式(HAVE_STRICT_REALTIME),使用CLOCK_MONOTONIC避免时钟漂移
  4. 资源可控:线程创建时配置栈大小、优先级、CPU亲和性
1.2 线程架构全景图
flowchart TB subgraph ParticipantThreadGroup["Participant级别线程组"] RE[ResourceEvent
event %u
定时事件中心] FC[FlowController
dds.asyn.%u.%u
异步发送线程] end subgraph TransportThreadGroup["传输层线程组"] UDP[UDPChannelResource
dds.udp.%u
每端口监听线程] TCP[TCPTransportInterface
io_context_thread_
ASIO事件循环] SHM[SharedMemChannelResource
dds.shm.%u
共享内存监听] end subgraph DataSharingThreadGroup["DataSharing线程组"] DSL[DataSharingListener
dds.dsha.%u
零拷贝数据监听] SHMW[SharedMemWatchdog
dds.shm.wdog
共享内存看门狗] end subgraph SynchronizationPrimitives["同步原语"] TCVM[TimedConditionVariable
CLOCK_MONOTONIC] TMU[TimedMutex
实时互斥锁] CQ[ConcurrentQueue
MPMC队列] DBQ[DBQueue
双缓冲MPSC队列] SEM[Semaphore
信号量] end RE -->|调度| TE[TimedEvent
心跳/保活/重传] FC -->|消费| FQ[FlowQueue
侵入式链表队列] UDP -->|回调| MR[MessageReceiver] TCP -->|回调| MR SHM -->|回调| MR DSL -->|通知| BR[BaseReader] style RE fill:#e1f5fe style FC fill:#e1f5fe style UDP fill:#fff3e0 style TCP fill:#fff3e0 style SHM fill:#fff3e0 style DSL fill:#f3e5f5

2. 关键组件详细分析

2.1 ResourceEvent - 集中式定时事件调度器

源码位置: Fast-DDS/src/cpp/rtps/resources/ResourceEvent.h

核心机制:

• 单线程事件循环:所有定时事件在同一个线程中处理,避免多线程竞争

• 双队列设计:pending_timers_(待处理)和 active_timers_(活跃,按触发时间升序排列)

• 条件变量等待:使用 TimedConditionVariable 精确等待到下一个定时器触发点

sequenceDiagram participant User as 用户线程 participant RE as ResourceEvent participant TE as TimedEventImpl participant CV as TimedConditionVariable User->>RE: register_timer(event) RE->>RE: timers_count_++ RE->>CV: notify_one() loop event_service() 事件循环 RE->>RE: update_current_time() RE->>RE: do_timer_actions() alt pending_timers_ 非空 RE->>RE: 处理pending到active RE->>RE: sort_timers() end RE->>RE: 计算next_trigger RE->>CV: wait_until(next_trigger) alt 有新事件通知 CV-->>RE: 唤醒 else 定时器到期 CV-->>RE: 超时唤醒 end end User->>RE: notify(event) RE->>RE: register_timer_nts(event) RE->>CV: notify_one()

关键代码片段:

ini 复制代码
// ResourceEvent.cpp:177-228
void ResourceEvent::event_service() {
    while (!stop_.load()) {
        update_current_time();
        do_timer_actions();  // 执行到期定时器
        
        std::unique_lock<TimedMutex> lock(mutex_);
        if (stop_.load()) break;
        
        // 允许其他线程操作定时器集合
        allow_vector_manipulation_ = true;
        cv_manipulation_.notify_all();
        
        // 计算下次触发时间
        std::chrono::steady_clock::time_point next_trigger =
            active_timers_.empty() ?
            current_time_ + std::chrono::seconds(1) :
            active_timers_[0]->next_trigger_time();
        
        cv_.wait_until(lock, next_trigger);
        allow_vector_manipulation_ = false;
    }
}

适用场景

  • 心跳定时器(Heartbeat)
  • 保活检测(Keep-alive)
  • 重传定时器(NACK响应)
  • 任何需要精确计时的后台任务

注意事项

  • 定时器回调在ResourceEvent线程执行,应避免长时间阻塞
  • 注册/注销定时器是线程安全的,但频繁操作会影响性能
  • 严格实时模式下使用CLOCK_MONOTONIC,不受系统时间调整影响

2.2 FlowController - 异步发送与流量控制

源码位置: Fast-DDS/src/cpp/rtps/flowcontrol/FlowControllerImpl.hpp

发布模式架构:

classDiagram class FlowControllerPureSyncPublishMode { +纯同步发送 +无旧样本机制 } class FlowControllerAsyncPublishMode { +eprosima::thread thread +atomic_bool running +TimedConditionVariable cv +TimedMutex changes_interested_mutex +atomic~uint32_t~ writers_interested_in_remove +异步发送新/旧样本 } class FlowControllerSyncPublishMode { +同步发送新样本 +异步发送旧样本 } class FlowControllerLimitedAsyncPublishMode { +int32_t max_bytes_per_period +milliseconds period_ms +uint32_t current_sent_bytes_ +带带宽限制的异步发送 } FlowControllerPureSyncPublishMode <|-- FlowControllerSyncPublishMode FlowControllerAsyncPublishMode <|-- FlowControllerSyncPublishMode FlowControllerAsyncPublishMode <|-- FlowControllerLimitedAsyncPublishMode

异步线程主循环:

flowchart TD A[run方法开始] --> B{async_mode.running?} B -->|否| C[退出] B -->|是| D{writers_interested_in_remove > 0?} D -->|是| B D -->|否| E[加锁mutex_] E --> F[加锁changes_interested_mutex] F --> G[add_interested_changes_to_queue_nts] G --> H{running && force_wait?} H -->|是| I[解锁mutex_] I --> J[wait条件变量] J --> K[触发带宽限制重置?] K --> G H -->|否| L[获取change_to_process] L --> M{change_to_process != nullptr?} M -->|否| B M -->|是| N[fast_check_is_there_slot_for_change] N --> O{有槽位?} O -->|否| B O -->|是| P[查找Writer] P --> Q[try_lock WriterMutex] Q --> R[deliver_sample_nts] R --> S{DELIVERED?} S -->|否| T[重新入队] S -->|是| U[work_done] U --> V[获取下一个change] V --> M

关键代码片段:

arduino 复制代码
// FlowControllerImpl.hpp:1395-1513
void run() {
    while (async_mode.running) {
        // 检查是否有writer想要移除样本
        if (0 != async_mode.writers_interested_in_remove) continue;
        
        std::unique_lock<fastdds::TimedMutex> lock(mutex_);
        CacheChange_t* change_to_process = nullptr;
        
        // 等待条件
        {
            std::unique_lock<fastdds::TimedMutex> in_lock(async_mode.changes_interested_mutex);
            sched.add_interested_changes_to_queue_nts();
            
            while (async_mode.running &&
                   (async_mode.force_wait() || 
                    nullptr == (change_to_process = sched.get_next_change_nts()))) {
                lock.unlock();
                bool ret = async_mode.wait(in_lock);
                // ...
            }
        }
        
        // 处理样本发送
        while (nullptr != change_to_process) {
            DeliveryRetCode ret = current_writer->deliver_sample_nts(
                change_to_process, async_mode.group, locator_selector,
                std::chrono::steady_clock::now() + std::chrono::hours(24));
            // ...
        }
    }
}

适用场景

  • ASYNCHRONOUS_WRITER模式:高吞吐场景,避免发送阻塞用户线程
  • 带宽限制场景:网络资源受限,需要流量整形
  • 多Writer公平调度:Round Robin调度器保证各Writer公平使用带宽

注意事项

  • 异步模式会增加延迟(队列排队时间)
  • 带宽限制模式下,超出限制的样本会等待下一个周期
  • 线程名为 dds.asyn.%u.%u(participant_id, async_index),便于调试
2.3 网络I/O线程模型

UDP传输

flowchart LR subgraph UDPChannel A[UDPChannelResource] -->|create_thread| B[监听线程
dds.udp.%u] B -->|阻塞receive_from| C[ASIO Socket] C -->|数据到达| D[MessageReceiver
OnDataReceived] end

关键代码UDPChannelResource.cpp:46-50):

scss 复制代码
auto fn = [this, locator]() {
    perform_listen_operation(locator);
};
thread(create_thread(fn, thread_config, "dds.udp.%u", locator.port));

TCP传输

flowchart TB subgraph TCPTransport A[TCPTransportInterface] -->|io_context_thread_| B[ASIO io_context
事件循环线程] B -->|async_accept| C[TCPAcceptor] B -->|async_read| D[TCPChannelResource] B -->|async_write| E[发送队列] F[perform_listen_operation] -->|独立线程| G[通道监听] end

共享内存传输

flowchart LR subgraph SharedMem A[SharedMemChannelResource] -->|create_thread| B[监听线程
dds.shm.%u] B -->|listener_->pop| C[共享内存
环形缓冲区] C -->|数据到达| D[MessageReceiver] end
2.4 DataSharingListener - 零拷贝数据监听

源码位置 : Fast-DDS/src/cpp/rtps/DataSharing/DataSharingListener.hpp

sequenceDiagram participant Writer as DataSharingWriter participant Notification as DataSharingNotification
共享内存通知区 participant DSL as DataSharingListener
dds.dsha.%u participant Reader as BaseReader Writer->>Notification: new_data = true Writer->>Notification: notification_cv.notify_all() loop run() 监听循环 DSL->>Notification: wait(notification_cv) Notification-->>DSL: 唤醒 alt new_data == true DSL->>DSL: process_new_data() DSL->>Reader: 回调数据到达 end alt writer_pools_changed_ DSL->>DSL: 重新加载Writer池 end end

3. 线程间通信机制

3.1 TimedConditionVariable - 实时条件变量

源码位置 : Fast-DDS/include/fastdds/utils/TimedConditionVariable.hpp

核心特性

  • 严格实时模式下使用 pthread_condattr_setclock(CLOCK_MONOTONIC)
  • 避免系统时间调整导致的等待异常
scss 复制代码
#if HAVE_STRICT_REALTIME && defined(__unix__)
#define CV_INIT_(x) pthread_condattr_init(&cv_attr_); \
    pthread_condattr_setclock(&cv_attr_, CLOCK_MONOTONIC); \
    pthread_cond_init(x, &cv_attr_);
#endif
3.2 线程安全队列

ConcurrentQueue(MPMC - 多生产者多消费者):

arduino 复制代码
template<typename T, typename Sequence = std::deque<T>>
class ConcurrentQueue {
    void push(O&& item) {
        std::unique_lock<std::mutex> lock(mutex_);
        queue_.emplace(std::forward<O>(item));
        lock.unlock();  // 先解锁再通知,避免唤醒线程立即阻塞
        has_data_.notify_one();
    }
    
    T wait_pop() {
        std::unique_lock<std::mutex> lock(mutex_);
        has_data_.wait(lock, [&]() { return !queue_.empty(); });
        auto popped_item = std::move(queue_.front());
        queue_.pop();
        return popped_item;
    }
};

DBQueue(双缓冲MPSC队列):

arduino 复制代码
template<class T>
class DBQueue {
    void Swap() {
        std::unique_lock<std::mutex> fgGuard(mForegroundMutex);
        std::unique_lock<std::mutex> bgGuard(mBackgroundMutex);
        std::queue<T>().swap(*mForegroundQueue);  // 清空前台
        std::swap(mForegroundQueue, mBackgroundQueue);
    }
    
    void Push(const T& item) {
        std::unique_lock<std::mutex> guard(mBackgroundMutex);
        mBackgroundQueue->push(item);
    }
};

适用场景:后台线程批量处理,前台线程无锁消费

4. 线程诊断与调试

4.1 线程命名规范
线程名格式 用途 源码位置
event %u ResourceEvent定时器线程 ResourceEvent.cpp
dds.asyn.%u.%u FlowController异步发送 FlowControllerImpl.hpp
dds.udp.%u UDP通道监听 UDPChannelResource.cpp
dds.shm.%u 共享内存通道监听 SharedMemChannelResource.hpp
dds.dsha.%u DataSharing监听 DataSharingListener.cpp
dds.shm.wdog 共享内存看门狗 SharedMemWatchdog.hpp
4.2 线程设置配置

ThreadSettings结构

ini 复制代码
struct ThreadSettings {
    uint32_t stack_size = 0;           // 线程栈大小
    int32_t priority = 0;              // 实时优先级(-1表示不设置)
    uint32_t affinity = 0;             // CPU亲和性掩码
    bool use_real_time = false;        // 是否使用实时调度
};
4.3 常见问题诊断
flowchart TD A[线程问题] --> B[CPU占用高?] B -->|是| C[检查ResourceEvent
定时器是否过于频繁] B -->|否| D[发送延迟高?] D -->|是| E[检查FlowController队列
是否堆积] D -->|否| F[数据接收丢失?] F -->|是| G[检查UDP/TCP
监听线程是否阻塞] F -->|否| H[共享内存异常?] H -->|是| I[检查SharedMemWatchdog
和DataSharingListener]

5. 参考数据源

类型 链接/引用 说明
源码 src/cpp/rtps/resources/ResourceEvent.h 定时事件调度器
源码 src/cpp/rtps/flowcontrol/FlowControllerImpl.hpp 流控制器实现
源码 include/fastdds/utils/TimedConditionVariable.hpp 实时条件变量
源码 src/cpp/utils/threading.hpp 线程创建工具
源码 src/cpp/utils/collections/concurrent_queue.h 并发队列
论文 Lock-Free Data Structures - Keir Fraser 无锁数据结构理论
规范 OMG DDS-RTPS RTPS协议标准
专利 US Patent 7,650,331 Data Distribution Service发布-订阅历史缓存
开源 Fast-DDS GitHub 官方仓库

6. 适用场景总结

场景 推荐配置 注意事项
低延迟实时系统 SYNCHRONOUS_WRITER + 严格实时编译选项 避免异步队列延迟
高吞吐大数据 ASYNCHRONOUS_WRITER + FlowController 监控队列深度
带宽受限网络 FlowControllerLimitedAsyncPublishMode 合理设置max_bytes_per_period
多核CPU优化 设置ThreadSettings.affinity 避免线程跨NUMA节点
共享内存零拷贝 DataSharing + SHM传输 注意共享内存段生命周期

以上是Fast-DDS 3.6.x线程模型与异步处理机制的完整分析,涵盖了:

  1. 核心组件:ResourceEvent定时调度、FlowController异步发送、网络I/O线程、DataSharing监听
  2. 同步原语:TimedConditionVariable(CLOCK_MONOTONIC)、TimedMutex、并发队列
  3. 线程间通信:双缓冲队列、侵入式链表队列、信号量

7. Win10 + WSL Ubuntu + VSCode + GDB 调试指南

7.1 环境准备

7.1.1 WSL Ubuntu 端安装依赖
bash 复制代码
# 安装编译工具和调试器
sudo apt update
sudo apt install -y build-essential cmake gdb ninja-build

# 安装 Fast-DDS 依赖(如果从头编译)
sudo apt install -y libasio-dev libtinyxml2-dev libssl-dev

# 验证 GDB 版本(建议 9.0+)
gdb --version
7.1.2 VSCode 扩展安装

在 Windows 端 VSCode 安装以下扩展:

  • Remote - WSL (Microsoft) - 连接 WSL
  • C/C++ (Microsoft) - IntelliSense 和调试支持
  • CMake Tools (Microsoft) - CMake 集成
ini 复制代码
cd Fast-DDS

# 创建 Debug 构建目录
mkdir -p build/debug && cd build/debug

# 配置 CMake(开启 Debug 符号)
cmake ../.. \
    -DCMAKE_BUILD_TYPE=Debug \
    -DCMAKE_INSTALL_PREFIX=/usr/local \
    -DCMAKE_CXX_FLAGS="-g -O0" \
    -DTHIRDPARTY_Asio=OFF \
    -DTHIRDPARTY_TinyXML2=OFF

# 编译(使用多核加速)
cmake --build . --parallel $(nproc)

# 安装(需要 sudo)
sudo cmake --install .

7.3 编译 Hello World 示例

bash 复制代码
cd /home/guang/code/opensource/Fast-DDS/examples/cpp/hello_world

# 创建构建目录
mkdir -p build && cd build

# 配置 CMake
cmake .. -DCMAKE_BUILD_TYPE=Debug

# 编译
cmake --build .

# 验证可执行文件
ls -la hello_world
file hello_world  # 应显示 "with debug_info"
bash 复制代码
# 在 WSL 中执行
code /home/guang/code/opensource/Fast-DDS/examples/cpp/hello_world

在项目根目录创建 .vscode/launch.json

bash 复制代码
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Hello World Publisher",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/build/hello_world",
            "args": ["publisher", "--samples", "10"],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}/build",
            "environment": [
                {
                    "name": "LD_LIBRARY_PATH",
                    "value": "/usr/local/lib:${env:LD_LIBRARY_PATH}"
                }
            ],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                },
                {
                    "description": "Set follow fork mode to child",
                    "text": "set follow-fork-mode child",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "build",
            "miDebuggerPath": "/usr/bin/gdb"
        },
        {
            "name": "Hello World Subscriber",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/build/hello_world",
            "args": ["subscriber", "--samples", "10"],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}/build",
            "environment": [
                {
                    "name": "LD_LIBRARY_PATH",
                    "value": "/usr/local/lib:${env:LD_LIBRARY_PATH}"
                }
            ],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "build",
            "miDebuggerPath": "/usr/bin/gdb"
        }
    ],
    "compounds": [
        {
            "name": "Publisher + Subscriber",
            "configurations": ["Hello World Subscriber", "Hello World Publisher"],
            "stopAll": true
        }
    ]
}
7.4.3 创建 tasks.json

在项目根目录创建 .vscode/tasks.json

bash 复制代码
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build",
            "type": "shell",
            "command": "cmake",
            "args": [
                "--build",
                "${workspaceFolder}/build",
                "--parallel",
                "$(nproc)"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "problemMatcher": ["$gcc"]
        },
        {
            "label": "clean",
            "type": "shell",
            "command": "rm -rf ${workspaceFolder}/build && mkdir ${workspaceFolder}/build",
            "group": "build"
        },
        {
            "label": "rebuild",
            "type": "shell",
            "command": "cmake --build ${workspaceFolder}/build --clean-first",
            "group": "build",
            "dependsOn": []
        }
    ]
}

7.5 关键调试断点设置

7.5.1 线程模型相关断点
断点位置 文件路径 说明
ResourceEvent::event_service src/cpp/rtps/resources/ResourceEvent.cpp:177 定时事件循环入口
FlowControllerImpl::run src/cpp/rtps/flowcontrol/FlowControllerImpl.hpp:1395 异步发送线程主循环
create_thread src/cpp/utils/threading.hpp:98 线程创建点
UDPChannelResource::perform_listen_operation src/cpp/rtps/transport/UDPChannelResource.cpp:61 UDP监听线程
DataSharingListener::run src/cpp/rtps/DataSharing/DataSharingListener.cpp:57 DataSharing监听线程
7.5.2 Hello World 业务断点
断点位置 文件路径 说明
main examples/cpp/hello_world/main.cpp:41 程序入口
PublisherApp::PublisherApp examples/cpp/hello_world/PublisherApp.cpp:40 Publisher构造
PublisherApp::publish examples/cpp/hello_world/PublisherApp.cpp:160 发布消息
PublisherApp::on_publication_matched examples/cpp/hello_world/PublisherApp.cpp:109 匹配回调
ListenerSubscriberApp::on_data_available examples/cpp/hello_world/ListenerSubscriberApp.cpp:126 数据到达回调

7.6 调试流程演示

7.6.1 单步调试 Publisher
scss 复制代码
// PublisherApp.cpp 关键断点位置
// 断点 1: 构造函数入口 (line 40)
PublisherApp::PublisherApp(const CLIParser::publisher_config& config, ...)
{
    // 断点 2: 创建 Participant (line 59)
    participant_ = factory->create_participant_with_default_profile(...);
    
    // 断点 3: 注册类型 (line 66)
    type_.register_type(participant_);
    
    // 断点 4: 创建 Publisher (line 71)
    publisher_ = participant_->create_publisher(pub_qos, ...);
    
    // 断点 5: 创建 Topic (line 80)
    topic_ = participant_->create_topic(topic_name, ...);
    
    // 断点 6: 创建 DataWriter (line 90)
    writer_ = publisher_->create_datawriter(topic_, writer_qos, this, StatusMask::all());
}

// 断点 7: 发布消息 (line 160)
bool PublisherApp::publish()
{
    // 断点 8: 等待匹配 (line 165)
    cv_.wait(matched_lock, ...);
    
    // 断点 9: 写入数据 (line 174)
    ret = (RETCODE_OK == writer_->write(&hello_));
}
7.6.2 线程调试技巧
python 复制代码
# GDB 常用线程命令
(gdb) info threads                    # 查看所有线程
(gdb) thread 2                        # 切换到线程2
(gdb) thread apply all bt             # 查看所有线程的调用栈
(gdb) thread apply 1 2 3 info locals  # 查看线程1,2,3的局部变量

# 设置线程特定断点
(gdb) break ResourceEvent.cpp:177 thread 2  # 只在线程2上中断

# 跟踪线程创建
(gdb) set breakpoint pending on
(gdb) break pthread_create

7.7 VSCode 调试界面操作

7.7.1 启动调试
  1. F5 或点击左侧调试图标
  2. 选择配置 "Hello World Publisher" 或 "Hello World Subscriber"
  3. 程序将在断点处暂停
7.7.2 调试快捷键
快捷键 功能
F5 继续/启动调试
F10 单步跳过
F11 单步进入
Shift+F11 单步跳出
F9 切换断点
Ctrl+Shift+F5 重启调试
Shift+F5 停止调试
7.7.3 观察窗口设置

在 VSCode 调试面板添加以下监视表达式:

scss 复制代码
// Publisher 监视
hello_.index()
hello_.message()
matched_
samples_
stop_

// Fast-DDS 内部(需源码)
participant_->getGuid()
writer_->getGuid()
type_.get_type_name()

// 线程相关
std::this_thread::get_id()

7.8 多进程联合调试

同时调试 Publisher 和 Subscriber:

json 复制代码
// launch.json 中已配置 compound
{
    "compounds": [
        {
            "name": "Publisher + Subscriber",
            "configurations": ["Hello World Subscriber", "Hello World Publisher"],
            "stopAll": true
        }
    ]
}

操作步骤

  1. 在 VSCode 调试面板选择 "Publisher + Subscriber"
  2. F5 启动,将同时启动两个调试会话
  3. 使用调试工具栏切换不同会话

7.9 常见问题排查

7.9.1 找不到共享库
bash 复制代码
# 错误:error while loading shared libraries: libfastdds.so.3
# 解决方案:
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH

# 或在 .bashrc 中永久添加
echo 'export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH' >> ~/.bashrc
source ~/.bashrc

# 验证
ldd /home/guang/code/opensource/Fast-DDS/examples/cpp/hello_world/build/hello_world
7.9.2 GDB 无法附加到进程
bash 复制代码
# 错误:ptrace: Operation not permitted
# 解决方案(WSL):
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope

# 或永久修改
sudo sysctl kernel.yama.ptrace_scope=0
7.9.3 调试信息缺失
ini 复制代码
# 验证可执行文件是否包含调试信息
readelf -S hello_world | grep debug

# 重新编译带 -g -O0
cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-g -O0"

7.10 高级调试技巧

7.10.1 条件断点

在 VSCode 中右键断点设置条件:

rust 复制代码
// 示例:只在 index == 5 时中断
hello_.index() == 5

// 示例:只在特定线程中断
std::this_thread::get_id() == std::thread::id(0x7f8e4c0a8700)
7.10.2 日志断点

使用 Fast-DDS 内置日志系统:

kotlin 复制代码
// 在代码中添加日志断点
EPROSIMA_LOG_INFO(PUBLISHER, "Debug: index = " << hello_.index());

// 或在 GDB 中
(gdb) break PublisherApp.cpp:174
(gdb) command
> silent
> printf "Publishing index: %d\n", hello_.index()
> continue
> end
7.10.3 核心转储分析
bash 复制代码
# 启用核心转储
ulimit -c unlimited

# 运行程序直到崩溃
./hello_world publisher

# 使用 GDB 分析核心文件
gdb ./hello_world core
(gdb) bt full          # 查看完整调用栈
(gdb) info registers   # 查看寄存器

7.11 参考配置完整文件

c_cpp_properties.json
bash 复制代码
{
    "configurations": [
        {
            "name": "Linux",
            "includePath": [
                "${workspaceFolder}/**",
                "/usr/local/include/fastdds/**",
                "/usr/local/include/fastcdr/**"
            ],
            "defines": [],
            "compilerPath": "/usr/bin/g++",
            "cStandard": "c11",
            "cppStandard": "c++11",
            "intelliSenseMode": "linux-gcc-x64",
            "configurationProvider": "ms-vscode.cmake-tools"
        }
    ],
    "version": 4
}
settings.json
bash 复制代码
{
    "cmake.buildDirectory": "${workspaceFolder}/build",
    "cmake.generator": "Ninja",
    "cmake.configureOnOpen": true,
    "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
    "debug.inlineValues": true,
    "debug.showBreakpointsInOverviewRuler": true
}
相关推荐
Java水解2 小时前
Spring Security 最佳实践:2026 实战指南
后端
0xDevNull2 小时前
JDK 25 新特性概览与实战教程
java·开发语言·后端
gelald2 小时前
Spring - 循环依赖
java·后端·spring
JavaGuide2 小时前
万字详解 RAG 基础概念:什么是 RAG? 为什么需要?工作原理是?
后端·ai编程
希望永不加班2 小时前
SpringBoot 多数据源配置(读写分离基础)
java·spring boot·后端·spring
Java成神之路-3 小时前
Spring AOP 核心进阶:切入点表达式 + 通知类型 + 环绕通知避坑指南(Spring系列8)
java·后端·spring
清汤饺子3 小时前
Cursor + Claude Code 组合使用心得:我为什么不只用一个 AI 编程工具
前端·javascript·后端
无责任此方_修行中3 小时前
Redis 的"三面"人生:开源世界的权力转移
redis·后端·程序员