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

C++多线程编程简介

C++多线程编程

概述

多线程编程允许在同一个程序中同时执行多个任务,从而提高程序的效率,特别是在处理 I/O 密集型或计算密集型任务时。C++11 引入了标准库中的多线程支持,使得 C++ 开发者能够更加方便地进行多线程编程。

线程基础

线程是程序中执行的最小单位,每个线程有自己的程序计数器、堆栈和局部变量。C++ 的 库提供了对线程的支持,允许我们在程序中启动多个并行的线程。

线程的创建与管理

要创建一个线程,首先需要包含 头文件。通过 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;
}

解释:

  • std::thread 构造函数接收一个函数作为参数,该函数将在新线程中执行。
  • t.join() 会阻塞主线程,直到 t 所表示的线程执行完成。
  • join 是线程同步的一种方式,确保主线程等待子线程完成后再继续执行。

多个线程

可以创建多个线程来执行不同的任务。每个线程都会执行一个独立的任务。

#include <iostream>
#include <thread>

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

void print_world() {
    std::cout << "World from thread!" << std::endl;
}

int main() {
    std::thread t1(print_hello);
    std::thread t2(print_world);

    t1.join();
    t2.join();

    return 0;
}
  • t1 和 t2 是两个不同的线程,它们分别执行 print_hello 和 print_world 函数。
  • join() 确保在程序结束之前,所有线程都完成。

线程的分离

除了 join,还有 detach 函数。使用 detach 后,线程将独立于主线程执行,它不会被等待完成,主线程可以继续执行。

#include <iostream>
#include <thread>

void print_message() {
    std::cout << "Message from detached thread!" << std::endl;
}

int main() {
    std::thread t(print_message);
    t.detach();  // 分离线程,主线程继续执行
    std::cout << "Main thread continues!" << std::endl;

    // 注意:如果主线程结束,分离线程可能未执行完成
    return 0;
}

注意:

  • 使用 detach 后,线程在后台执行,主线程可以退出,不会等待它的完成。若主线程结束时子线程仍在运行,则可能会出现未定义的行为,因此要小心使用 detach。

线程同步

多线程编程常常面临多个线程共享资源的情况。如果多个线程同时访问和修改共享数据,就会引发数据竞争问题。这时,需要对共享资源进行同步。

互斥量(Mutex)

互斥量是保护共享资源的一种机制,它确保同一时刻只有一个线程能访问共享资源。

#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx;  // 互斥量

void print_message(const std::string &message) {
    mtx.lock();  // 上锁
    std::cout << message << std::endl;
    mtx.unlock();  // 解锁
}

int main() {
    std::thread t1(print_message, "Hello from thread 1");
    std::thread t2(print_message, "Hello from thread 2");

    t1.join();
    t2.join();

    return 0;
}
  • std::mutex mtx 定义了一个互斥量,用来保护共享资源(此处是 std::cout)。
  • mtx.lock() 获取锁,确保当前线程独占对 cout 的访问。
  • mtx.unlock() 释放锁,允许其他线程获取锁。

std::lock_guard 和 std::unique_lock

为了避免手动调用 lock() 和 unlock(),C++ 提供了 std::lock_guard 和 std::unique_lock,它们在作用域结束时自动释放锁,避免忘记解锁。

#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx;  // 互斥量

void print_message(const std::string &message) {
    std::lock_guard<std::mutex> lock(mtx);  // 上锁
    std::cout << message << std::endl;
    // 自动解锁,当 lock_guard 对象超出作用域时
}

int main() {
    std::thread t1(print_message, "Hello from thread 1");
    std::thread t2(print_message, "Hello from thread 2");

    t1.join();
    t2.join();

    return 0;
}
  • std::lock_guard 自动获取和释放锁,使代码更加简洁安全。

std::condition_variable

std::condition_variable 用于在多个线程之间同步,通常用于实现线程之间的等待与通知机制。

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void print_id(int id) {
    std::unique_lock<std::mutex> lck(mtx);
    while (!ready) cv.wait(lck);  // 等待条件满足
    std::cout << "Thread " << id << std::endl;
}

void go() {
    std::unique_lock<std::mutex> lck(mtx);
    ready = true;  // 改变条件
    cv.notify_all();  // 通知所有线程
}

int main() {
    std::thread threads[10];
    for (int i = 0; i < 10; ++i) 
        threads[i] = std::thread(print_id, i);

    std::cout << "Waiting for threads to be ready..." << std::endl;
    go();  // 通知线程

    for (auto& th : threads) th.join();
    return 0;
}
  • cv.wait(lck) 会使当前线程等待直到 ready 为 true。
  • cv.notify_all() 会通知所有等待的线程继续执行。

原子操作

原子操作是不会被中断的操作,它对于多线程同步非常有用。在 C++11 中,std::atomic 提供了对基本数据类型的原子操作支持。

#include <iostream>
#include <thread>
#include <atomic>

std::atomic<int> counter(0);

void increment() {
    for (int i = 0; i < 1000; ++i)
        ++counter;  // 原子增加
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);

    t1.join();
    t2.join();

    std::cout << "Final counter value: " << counter.load() << std::endl;
    return 0;
}
  • std::atomic 确保对 counter 的操作是原子的,不会被多个线程同时修改,避免了数据竞争。

http://www.kler.cn/a/612711.html

相关文章:

  • NetMizer-日志管理系统-远程命令执行漏洞挖掘
  • 经典优化算法:遗传算法(Genetic Algorithm, GA)
  • Python正则表达式(二)
  • docker中安装 python
  • GPT-SoVITS本地部署:低成本实现语音克隆远程生成音频全流程实战
  • 课程5. 机器学习的核心方法
  • 简单介绍My—Batis
  • 亚马逊云科技全面托管DeepSeek-R1模型现已上线
  • 解决 Gin Web 应用中 Air 热部署无效的问题
  • pyqt第一个窗口程序
  • el-table下的复选框关联勾选
  • 【leetcode hot 100 74】搜索二维矩阵
  • 我的创作纪念日——三周年
  • [识记]Mysql8 远程授权
  • 北斗导航 | 改进奇偶矢量法的接收机自主完好性监测算法原理,公式,应用,RAIM算法研究综述,matlab代码
  • redis部署架构
  • Python----计算机视觉处理(Opencv:直方图均衡化)
  • python之并发编程
  • Vue3 实战:基于 mxGraph 与 WebSocket 的动态流程图构建
  • AugFPN