c++ 多线程(三)

Lambda 表达式作为 std::thread 参数

    • [1. 基本使用方法](#1. 基本使用方法)
      • [1.1 最简单的 Lambda 线程](#1.1 最简单的 Lambda 线程)
      • [1.2 带参数的 Lambda](#1.2 带参数的 Lambda)
    • [2. 捕获列表详解](#2. 捕获列表详解)
      • [2.1 不同的捕获方式](#2.1 不同的捕获方式)
    • [3. 应用示例](#3. 应用示例)
      • [3.1 带返回值的 Lambda 线程](#3.1 带返回值的 Lambda 线程)
    • [4. 注意事项和陷阱](#4. 注意事项和陷阱)
      • [4.1 生命周期问题](#4.1 生命周期问题)
      • [4.2 异常安全](#4.2 异常安全)

1. 基本使用方法

1.1 最简单的 Lambda 线程

cpp 复制代码
#include <iostream>
#include <thread>

int main() {
    // 基本 lambda 表达式
    std::thread t([]() {
        std::cout << "线程正在运行" << std::endl;
    });
    
    t.join();
    return 0;
}

1.2 带参数的 Lambda

cpp 复制代码
#include <iostream>
#include <thread>

int main() {
    int value = 42;
    
    std::thread t([value]() {
        std::cout << "捕获的值: " << value << std::endl;
    });
    
    t.join();
    
    // 直接传递参数给 lambda
    std::thread t2([](int x, const std::string& str) {
        std::cout << x << ", " << str << std::endl;
    }, 100, "Hello");
    
    t2.join();
    return 0;
}

2. 捕获列表详解

2.1 不同的捕获方式

cpp 复制代码
#include <iostream>
#include <thread>
#include <vector>

int main() {
    int a = 1, b = 2, c = 3;
    
    // 1. 值捕获 [a, b]
    std::thread t1([a, b]() {
        std::cout << "值捕获: a=" << a << ", b=" << b << std::endl;
        // a = 10; // 错误:const 值,不能修改
    });
    
    // 2. 引用捕获 [&a, &b]
    std::thread t2([&a, &b]() {
        a = 10;
        b = 20;
        std::cout << "引用捕获: 修改后 a=" << a << ", b=" << b << std::endl;
    });
    
    // 3. 混合捕获 [a, &b]
    std::thread t3([a, &b]() {
        // a 是值,b 是引用
        b = a * 2;
        std::cout << "混合捕获: a=" << a << ", b=" << b << std::endl;
    });
    
    // 4. 默认值捕获 [=]
    std::thread t4([=]() {
        std::cout << "默认值捕获: a=" << a << ", b=" << b << ", c=" << c << std::endl;
    });
    
    // 5. 默认引用捕获 [&]
    std::thread t5([&]() {
        a = 100;
        b = 200;
        c = 300;
        std::cout << "默认引用捕获: 修改所有变量" << std::endl;
    });
    
    // 6. 可变 lambda(允许修改值捕获的变量)
    std::thread t6([a]() mutable {
        int temp = a;  // 可以修改副本
        temp = 999;
        std::cout << "mutable: 修改副本为 " << temp << std::endl;
    });
    
    t1.join(); t2.join(); t3.join(); 
    t4.join(); t5.join(); t6.join();
    
    std::cout << "最终值: a=" << a << ", b=" << b << ", c=" << c << std::endl;
    return 0;
}

3. 应用示例

3.1 带返回值的 Lambda 线程

cpp 复制代码
#include <iostream>
#include <thread>
#include <future>
#include <functional>

int main() {
    // 方法1:使用 std::async 获取返回值
    auto future1 = std::async([](int a, int b) -> int {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        return a + b;
    }, 10, 20);
    
    int result1 = future1.get();
    std::cout << "结果1: " << result1 << std::endl;
    
    // 方法2:使用 promise/future
    std::promise<int> promise;
    std::future<int> future2 = promise.get_future();
    
    std::thread t2([&promise]() {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        promise.set_value(42);
    });
    
    int result2 = future2.get();
    std::cout << "结果2: " << result2 << std::endl;
    
    t2.join();
    
    // 方法3:使用 packaged_task
    std::packaged_task<int(int, int)> task([](int x, int y) {
        return x * y;
    });
    
    std::future<int> future3 = task.get_future();
    std::thread t3(std::move(task), 6, 7);
    
    int result3 = future3.get();
    std::cout << "结果3: " << result3 << std::endl;
    
    t3.join();
    return 0;
}

4. 注意事项和陷阱

4.1 生命周期问题

cpp 复制代码
#include <iostream>
#include <thread>
#include <memory>

void dangerous_example() {
    std::thread t;
    
    {
        int local_var = 42;
        // 危险!捕获了局部变量的引用
        t = std::thread([&local_var]() {
            std::this_thread::sleep_for(std::chrono::seconds(1));
            std::cout << "local_var = " << local_var << std::endl;  // 未定义行为!
        });
    }  // local_var 在这里被销毁
    
    t.join();  // 访问已销毁的变量!
}

void safe_example() {
    // 方法1:值捕获
    {
        int value = 100;
        std::thread t1([value]() {  // 安全:复制值
            std::cout << "值捕获: " << value << std::endl;
        });
        t1.join();
    }
    
    // 方法2:使用智能指针共享所有权
    {
        auto shared_data = std::make_shared<int>(200);
        std::thread t2([shared_data]() {  // 安全:共享所有权
            std::cout << "智能指针: " << *shared_data << std::endl;
        });
        t2.join();
    }
    
    // 方法3:等待局部作用域结束
    {
        int local_var = 300;
        std::thread t3([&local_var]() {
            std::cout << "引用捕获(短时间内): " << local_var << std::endl;
        });
        t3.join();  // 在 local_var 销毁前 join
    }
}

4.2 异常安全

cpp 复制代码
#include <iostream>
#include <thread>
#include <stdexcept>

void exception_example() {
    // lambda 中的异常不会传播到主线程
    std::thread t([]() {
        try {
            throw std::runtime_error("线程内部错误");
        } catch (const std::exception& e) {
            std::cerr << "捕获到异常: " << e.what() << std::endl;
        }
    });
    
    t.join();
    
    // 未捕获的异常会终止程序
    std::thread t2([]() {
        throw std::runtime_error("未捕获的异常");
    });
    
    t2.join();  // 程序可能在此终止
}

class ExceptionSafeThread {
private:
    std::thread worker_;
    
public:
    ExceptionSafeThread() {
        worker_ = std::thread([this]() {
            try {
                this->worker_func();
            } catch (const std::exception& e) {
                std::cerr << "线程异常: " << e.what() << std::endl;
            } catch (...) {
                std::cerr << "未知异常" << std::endl;
            }
        });
    }
    
    void worker_func() {
        // 工作逻辑
    }
    
    ~ExceptionSafeThread() {
        if (worker_.joinable()) {
            worker_.join();
        }
    }
};
相关推荐
2503_928411562 小时前
12.9 Vue3+Vuex+Js+El-Plus+vite(项目搭建)
开发语言·javascript·ecmascript
卓码软件测评2 小时前
第三方软件验收评测机构【Gatling安装指南:Java环境配置和IDE插件安装】
java·开发语言·ide·测试工具·负载均衡
weixin_307779132 小时前
Jenkins中的Jakarta Activation API插件:功能、使用与最佳实践
运维·开发语言·ci/cd·自动化·jenkins
点云SLAM2 小时前
C++ 中traits 类模板(type traits / customization traits)设计技术深度详解
c++·算法·c++模板·c++高级应用·traits 类模板·c++17、20·c++元信息
weixin_439930642 小时前
前端js日期计算跨月导致的错误
开发语言·前端·javascript
liu****3 小时前
9.二叉树(一)
c语言·开发语言·数据结构·算法·链表
她说..3 小时前
Spring AOP场景2——数据脱敏(附带源码)
java·开发语言·java-ee·springboot·spring aop
sunly_3 小时前
Flutter:showModalBottomSheet底部弹出完整页面
开发语言·javascript·flutter
水饺编程3 小时前
第3章,[标签 Win32] :处理 WM_PRINT 消息
c语言·c++·windows·visual studio