当前位置: 首页 > news >正文

C++ 线程和线程管理

1. C++ 线程和线程管理

C++11 引入了线程支持,可以通过 std::thread 创建和管理线程。以下是线程管理的关键概念:

1.1 创建线程

使用 std::thread 类来创建一个线程并启动该线程:

#include <iostream>
#include <thread>

void print_hello() {
    std::cout << "Hello from thread!" << std::endl;
}

int main() {
    std::thread t(print_hello);  // 创建线程并执行print_hello函数
    t.join();  // 主线程等待子线程执行完成
    return 0;
}
  • t.join():会阻塞主线程,直到线程 t 完成其任务。
  • t.detach():会将线程与主线程分离,主线程不会等待线程的完成。
1.2 线程与主线程分离(detach()
std::thread t(print_hello);
t.detach();  // 线程将在后台运行,主线程不再等待它
  • 分离线程意味着主线程无法再与之交互,且程序结束时,分离的线程会被系统自动清理。
  • 如果分离的线程在主线程退出时仍然活跃,可能会造成资源泄露或访问未定义行为。
1.3 线程的生命周期

线程的生命周期由创建线程的 std::thread 对象管理。如果线程对象在析构时未调用 join()detach(),程序将抛出异常,提示线程没有正确管理。


2. 锁和互斥量

在多线程环境中,锁和互斥量用于同步线程访问共享资源,以避免数据竞态和死锁等问题。C++ 提供了多种锁和互斥量类型来应对不同的同步需求。

2.1 std::mutex(互斥量)

std::mutex 是最常用的锁类型,确保同一时刻只有一个线程能访问共享资源。

std::mutex mtx;

void print_hello(int id) {
    std::lock_guard<std::mutex> lock(mtx);
    std::cout << "Thread " << id << " is working" << std::endl;
}
  • std::lock_guard:提供 RAII 风格的锁管理,自动加锁和解锁。
  • std::unique_lock:功能更强大,支持手动解锁和锁定、延迟锁定等。
2.2 std::recursive_mutex(递归互斥量)

std::recursive_mutex 允许同一线程多次加锁而不会死锁,适用于递归的场景。

std::recursive_mutex rmtx;

void recursive_print(int id, int count) {
    std::lock_guard<std::recursive_mutex> lock(rmtx);
    if (count > 0) {
        std::cout << "Thread " << id << " printing recursively, count: " << count << std::endl;
        recursive_print(id, count - 1);
    }
}
  • 适合需要递归操作的场景,例如递归函数中的锁保护。
2.3 std::shared_mutex(共享互斥量)

std::shared_mutex 允许多个线程共享读取数据的锁,但写入数据时会独占访问权。

std::shared_mutex smtx;

void read_data(int id) {
    std::shared_lock<std::shared_mutex> lock(smtx);  // 共享锁
    std::cout << "Thread " << id << " is reading data." << std::endl;
}

void write_data(int id) {
    std::unique_lock<std::shared_mutex> lock(smtx);  // 独占锁
    std::cout << "Thread " << id << " is writing data." << std::endl;
}
  • std::shared_lock:获取共享锁,多个线程可以同时读取资源。
  • std::unique_lock:获取独占锁,确保只有一个线程能够写入数据。
2.4 std::timed_mutexstd::try_lock

std::timed_mutex 允许线程尝试在指定时间内获取锁,而 std::try_lock 则允许线程立即返回尝试锁定结果。

std::timed_mutex tmtx;

void try_lock_example() {
    if (tmtx.try_lock_for(std::chrono::seconds(1))) {
        std::cout << "Lock acquired successfully" << std::endl;
        tmtx.unlock();
    } else {
        std::cout << "Lock attempt timed out" << std::endl;
    }
}
  • try_lock_for():尝试在指定的时间内获取锁。
  • try_lock():立即返回是否能够成功获取锁。

3. 线程同步:std::condition_variable

std::condition_variable 用于线程间的通知机制,通过它,线程可以在特定条件发生时被唤醒。主要的两种操作是 notify_one()notify_all()

3.1 std::condition_variable 基本用法
std::mutex mtx;
std::condition_variable cv;

void wait_for_data() {
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, []{ return data_ready; });  // 等待条件满足
    // 数据准备好后继续执行
}
  • wait():阻塞当前线程,直到条件变量被通知。
  • notify_one():唤醒一个等待线程。
  • notify_all():唤醒所有等待线程。
3.2 notify_one()notify_all() 的区别:
  • notify_one():唤醒一个线程,适合只需要唤醒一个线程的场景。
  • notify_all():唤醒所有等待的线程,适合所有线程都需要响应某个条件时。
void producer() {
    {
        std::lock_guard<std::mutex> lock(mtx);
        data_ready = true;
    }
    cv.notify_all();  // 唤醒所有等待线程
}

void consumer(int id) {
    std::unique_lock<std::mutex> lock(mtx);
    while (!data_ready) cv.wait(lock);  // 等待数据准备好
    std::cout << "Consumer " << id << " is processing data" << std::endl;
}

4. 常见的锁类型总结

锁类型适用场景特点
std::mutex基本的互斥锁,保护共享资源不被并发访问不可递归,同一时间只有一个线程持有
std::recursive_mutex需要递归加锁的场景允许同一线程多次加锁
std::shared_mutex读多写少的场景,如缓存系统、数据库读写操作等读线程共享,写线程独占
std::timed_mutex需要超时控制的场景可在一定时间内尝试获取锁
std::lock_guard用于简化锁的管理,RAII 风格的锁管理自动加锁和解锁
std::unique_lock更灵活的锁管理,支持延迟锁定、解锁、重锁等支持手动解锁与重新锁定

总结

  • 线程创建与管理:C++11 提供了 std::thread 用于创建和管理线程,支持线程同步与并发操作。
  • 锁与互斥量:通过 std::mutexstd::recursive_mutexstd::shared_mutexstd::timed_mutex 等锁类型实现线程间资源同步,避免数据竞态。
  • 条件变量同步:使用 std::condition_variable 实现线程间的通知和等待机制,notify_one()notify_all() 用于唤醒等待线程。
  • RAII 风格的锁管理:使用 std::lock_guardstd::unique_lock 来简化锁的管理,确保锁的自动释放。

相关文章:

  • Hadoop 基础原理
  • 小狐狸ai3.1.2版本源码无授权版本内 含搭建教程+各种上线教程
  • sql server 数据库 锁教程及锁操作
  • DeepSeek - R1:模型架构深度解析
  • 汉诺塔问题详解:递归与分治的经典案例
  • S7-200中的软件及编程
  • 【强化学习的数学原理】第08课-值函数近似-笔记
  • 用deepseek学大模型08-卷积神经网络(CNN)
  • Spring MVC 的核心以及执行流程
  • Spring如何去解决循环依赖问题的?
  • 互信息的定义与公式
  • SVN 创建版本库
  • MaxKB本地部署向量数据库出现HeaderTooLarge报错
  • dify实现分析-rag-文档内容提取
  • HTTP的“对话”逻辑:请求与响应如何构建数据桥梁?
  • DDD - 可能会用到的分布式事务
  • 深入浅出地讲解rvbacktrace原理
  • Ubuntu如何利用.ibd文件恢复MySQL数据?
  • 算法基础 -- Fenwick树的实现原理
  • python中使用数据库sqlite3
  • 网络推广培训推荐/百度热搜关键词排名优化
  • 行业推广做哪个网站好/app推广引流
  • 网站顶部怎么做新浪链接/seo技术助理
  • 网站底部图标代码/怎么样自己创建网站
  • 网站三级页怎么做/免费招收手游代理
  • 织梦 大型综合旅游网站 源码/百度新闻官网首页