C++11 多线程并发编程,thread,lock,lock_guard,unique_lock使用
发布日期:2021-05-10 01:23:25 浏览次数:19 分类:精选文章

本文共 4397 字,大约阅读时间需要 14 分钟。

thread类与多线程编程

在C++中,thread类是进行多线程编程的核心工具,可以通过它创建和管理子线程。了解thread类的成员函数和使用方法,是掌握多线程编程的基础。

thread成员函数解析

  • join()方法

    join()方法用于阻塞主线程,等待子线程执行完成。如果子线程已经完成或被终止,join()立即返回。

  • detach()方法

    detach()方法取消主线程与子线程之间的关联,子线程独立执行。主线程会等到所有子线程完成后自动退出。

  • joinable()方法

    joinable()返回一个布尔值,用于检查当前线程是否可以被另一个线程阻塞等待。可以通过反复调用该方法判断线程状态。

  • id()方法

    id()方法用于获取当前线程的内核线程ID,用于排查线程相关问题或在调试中跟踪线程。

  • 互斥量(mutex)的使用

    互斥量是实现线程安全的核心机制。使用互斥量控制共享资源的访问,避免竞态条件和死锁。

    <mutex>概述

    互斥量有两种主要功能:

    • lock()unlock():加锁和解锁操作。
    • 原子操作:确保在加锁和解锁期间,资源的访问是安全的。

    互斥量的加锁与解锁

  • 使用std::lock_guard

    std::lock_guard是一个类模板,可以替代传统的lock()unlock()。它的构造在加锁,析构在解锁。

  • std::lock()函数

    std::lock()用于加多个互斥量锁。如果所有锁都加锁,才会成功。否则,返回不加锁。

  • std::try_to_lock策略

    std::unique_lock中,std::try_to_lock是另一个加锁方式,可以尝试加锁,如果失败则直接返回,不阻塞。

  • unique_lock的灵活性

    std::unique_lock提供了更强的灵活性,支持以下参数:

    • adopt_lock:将现有的锁 hObject转移所有权。
    • try_to_lock:非阻塞加锁方式。
    • defer_lock:无需提前加锁,直接放置unique_lock对象。

    unique_lock的成员函数

    • lock():阻塞加锁,与std::lock()类似。
    • unlock():手动解锁。
    • try_lock():非阻塞加锁。
    • release():释放unique_lock管理的互斥量,转移所有权。

    unique_lock的所有权转移

    unique_lock支持将互斥量的所有权转移到另一个unique_lock对象。可以通过std::move操作符或构造函数完成。

    sleep方法

    在多线程编程中,有时需要让线程暂停一定时间,使用std::this_thread::sleep_forsleep_until

    #include 
    // 阻塞2秒
    std::chrono::milliseconds delay(2000);
    std::this_thread::sleep_for(delay);

    代码示例

    下面是一个简单的多线程示例:

    #include 
    #include
    #include
    using namespace std;
    class B {
    private:
    queue
    que;
    mutex my_mutex;
    condition_variable cond;
    public:
    void insert() {
    for (int i = 0; i < 1000; ++i) {
    {
    lock_guard
    guard(my_mutex);
    que.push(i);
    cond.notify_one();
    }
    // 不加锁的可见界面
    }
    }
    void pop() {
    while (!que.empty()) {
    {
    lock_guard
    guard(my_mutex); int num = que.front(); que.pop(); // 可以手动解锁或由unique_lock自动解锁 } // 可以等待或不等待 } } }; int main() { B b; thread insert_thread(&B::insert, &b); thread pop_thread(&B::pop, &b); insert_thread.join(); pop_thread.join(); cout << "完成" << endl; return 0; }

    条件变量的使用

    条件变量提供了一种有效的等待机制。通过与互斥量和条件变量组合,可以实现线程间的同步与通信。

    #include 
    #include
    #include
    using namespace std;
    class A {
    public:
    vector
    vec;
    mutex mutex;
    condition_variable cond;
    void produce() {
    for (int i = 0; i < 100; ++i) {
    {
    lock_guard
    guard(mutex);
    vec.push_back(i);
    cond.notify_one();
    }
    // 可以添加其他操作
    }
    }
    void consume() {
    while (!vec.empty()) {
    {
    lock_guard
    guard(mutex); int num = vec.front(); vec.pop(); cout << "消费了:" << num << endl; // 可以添加其他操作 } // 手动释放 } } }; int main() { A a; thread produce_thread(&A::produce, &a); thread consume_thread(&A::consume, &a); produce_thread.join(); return 0; }

    originalTask完成后

    这个系统中的任务可能是耗时的,需要确保其能完成。如果任务长时间未完成,可以使用原子操作来跟踪和管理。

    #include 
    #include
    #include
    using namespace std;
    class Task {
    private:
    atomic
    count;
    mutex mutex;
    public:
    Task() : count(0) {}
    void run() {
    for (int i = 0; i < 100000; ++i) {
    {
    lock_guard
    guard(mutex);
    count++;
    }
    }
    }
    int get_count() {
    lock_guard
    guard(mutex); return count; } }; int main() { Task t; thread t_thread(&Task::run, &t); t_thread.join(); cout << "跑完一个循环,计数器:" << t.get_count() << endl; return 0; }

    使用std::async

    std::async用于创建asynchronous Task。我们可以根据需求选择不同的策略:

    • std::launch::async:立即创建新线程执行任务。
    • std::launch::deferred:延迟执行任务,等到get()wait()被调用。
    #include 
    #include
    #include
    #include
    using namespace std;
    struct MyTask {
    MyTask(int delay) : delay_(delay) {}
    // 仅存在于lambda表达式中区域
    ~MyTask() {}
    void operator()() const {
    cout << "任务执行完毕" << endl;
    }
    private:
    int delay_;
    };
    int main() {
    auto task = make_unique
    (2000);
    // 创建一个asynchronous Task
    // std::launch可以选择策略
    auto result = async(task, launch::async);
    result.wait_for(1s);
    cout << "已获取到结果" << endl;
    return 0;
    }

    以上示例展示了如何在多线程中安全地管理共享资源、传递任务,以及如何进行异步操作。通过合理使用互斥量和条件变量,可以实现线程安全和高效的任务管理。

    上一篇:单例模式(C++)以及共享问题
    下一篇:各种排序算法C++实现

    发表评论

    最新留言

    很好
    [***.229.124.182]2025年03月31日 07时00分45秒