C++线程基础使用方法

news2024/11/19 16:55:10

文章目录

      • **1. 什么是线程**
      • **2. C++ 中的线程库**
      • **3. 创建线程**
        • 基本用法
        • 使用 Lambda 表达式
        • 使用类成员函数
      • **4. 管理线程**
        • `join` 和 `detach`
        • 检查线程是否可加入
      • **5. 数据共享与同步**
        • 数据竞争问题
        • 使用互斥锁 (`std::mutex`)
        • 死锁与避免
      • **6. 条件变量**
      • **7. 线程间通信**
        • 使用 `std::future` 和 `std::promise`
      • **8. 总结**


C++ 中的线程是指程序中能够独立执行的一条控制流。线程允许在同一个进程中并发运行多个任务,从而提高程序的性能和响应性。C++11 标准引入了对线程的原生支持,通过 <thread> 标准库提供了一套工具来管理线程。


1. 什么是线程

线程是程序执行的基本单位,多个线程可以共享同一进程的资源(如内存、文件句柄等)。线程的使用场景包括:

  • 多任务并行处理(如同时处理用户输入和后台计算)。
  • 提高程序性能(利用多核 CPU)。
  • 异步操作(如非阻塞 I/O)。

2. C++ 中的线程库

C++ 标准库中的线程功能由头文件 <thread> 提供,主要包括:

  • std::thread:用于创建和管理线程。
  • std::mutex:用于线程同步,防止数据竞争。
  • std::condition_variable:用于线程间的条件通知。
  • std::futurestd::promise:用于线程间的结果传递。

3. 创建线程

基本用法
#include <iostream>
#include <thread>

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

int main() {
    std::thread t(task); // 创建并启动线程
    t.join();            // 等待线程完成
    return 0;
}

说明:

  • std::thread t(task):启动线程 t,执行函数 task
  • t.join():主线程等待子线程完成。如果没有调用 join()detach(),程序会报错。
使用 Lambda 表达式
#include <iostream>
#include <thread>

int main() {
    std::thread t([] {
        std::cout << "Hello from Lambda thread!" << std::endl;
    });
    t.join();
    return 0;
}
使用类成员函数
#include <iostream>
#include <thread>

class Task {
public:
    void operator()() const {
        std::cout << "Hello from class thread!" << std::endl;
    }
};

int main() {
    Task task;
    std::thread t(task); // 使用类的调用运算符
    t.join();
    return 0;
}

4. 管理线程

joindetach
  • join():等待线程执行完成。线程执行完成前,主线程会被阻塞。
  • detach():将线程与主线程分离,线程在后台继续运行。分离的线程无法再被主线程管理。
std::thread t(task);
t.detach();  // t 独立运行
检查线程是否可加入
if (t.joinable()) {
    t.join();
}

5. 数据共享与同步

数据竞争问题

多个线程共享数据时,可能会发生数据竞争(多个线程同时访问和修改同一资源)。

#include <iostream>
#include <thread>

int counter = 0;

void increment() {
    for (int i = 0; i < 100000; ++i) {
        ++counter;
    }
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);
    t1.join();
    t2.join();
    std::cout << "Counter: " << counter << std::endl; // 结果可能不正确
    return 0;
}
使用互斥锁 (std::mutex)

互斥锁可以防止数据竞争。

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

int counter = 0;
std::mutex mtx;

void increment() {
    for (int i = 0; i < 100000; ++i) {
        std::lock_guard<std::mutex> lock(mtx); // 自动管理锁
        ++counter;
    }
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);
    t1.join();
    t2.join();
    std::cout << "Counter: " << counter << std::endl; // 结果正确
    return 0;
}
死锁与避免

使用多个互斥锁时可能会发生死锁。可以使用 std::lock 同时锁定多个资源。

std::lock(mutex1, mutex2);

6. 条件变量

条件变量用于线程间的同步,使一个线程等待另一个线程的通知。

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

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

void worker() {
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, [] { return ready; }); // 等待通知
    std::cout << "Worker is running!" << std::endl;
}

int main() {
    std::thread t(worker);

    std::this_thread::sleep_for(std::chrono::seconds(1));
    {
        std::lock_guard<std::mutex> lock(mtx);
        ready = true;
    }
    cv.notify_one(); // 通知线程
    t.join();
    return 0;
}

7. 线程间通信

使用 std::futurestd::promise
  • std::promise:允许线程间传递值。
  • std::future:用于获取异步结果。
#include <iostream>
#include <thread>
#include <future>

void compute(std::promise<int> p) {
    p.set_value(42); // 设置结果
}

int main() {
    std::promise<int> p;
    std::future<int> f = p.get_future();

    std::thread t(compute, std::move(p));
    std::cout << "Result: " << f.get() << std::endl; // 获取结果
    t.join();
    return 0;
}

8. 总结

C++ 的线程功能强大,可以用于实现高效的多任务并行处理。然而,开发多线程程序需要注意以下几点:

  1. 数据同步:通过 std::mutex 或其他机制避免数据竞争。
  2. 死锁问题:小心使用多个锁,合理设计锁的顺序。
  3. 资源管理:使用智能指针和 std::lock_guard 等工具确保资源安全。

正确地使用线程可以极大地提升程序的性能,但也增加了程序的复杂性和调试难度。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2243508.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DDRPHY数字IC后端设计实现系列专题之数字后端floorplanpowerplan设计

3.2.3 特殊单元的布局 布图阶段除了布置 I/O 单元和宏单元&#xff0c;在 28nm 制程工艺时&#xff0c;还需要处理两种特 殊的物理单元&#xff0c;Endcap 和 Tapcell。 DDRPHY数字IC后端设计实现系列专题之后端设计导入&#xff0c;IO Ring设计 &#xff08;1&#xff09;拐…

css uniapp背景图宽度固定高度自适应可以重复

page {height: 100%;background-image: url(https://onlinekc.a.hlidc.cn/uploads/20241115/350f94aaf493d05625a7ddbc86c7804e.png);background-repeat: repeat;background-size: contain;} 如果不要重复 把background-repeat: repeat;替换background-repeat: no-repeat;

CC工具箱使用指南:【CAD导出界址点Excel】

一、简介 群友定制工具。 面图层导出界址点Excel表之前已经做过好几个&#xff0c;这个工具则是将CAD导出Excel。 CAD数据如下&#xff1a; 工具将如上截图中的边界线导出界址点Excel&#xff0c;并记录下面内的文字。 二、工具参数介绍 点击【定制工具】组里的【CAD导出界…

输出比较简介

输出比较简介 主要是用来输出PWM波形&#xff0c;这个波形是驱动电机的&#xff08;智能车和机器人等&#xff09;必要条件 OC&#xff08;Output Compare&#xff09;输出比较&#xff0c;还有IC&#xff0c;全称是Input Capture&#xff0c;意为输入捕获&#xff0c;还有CC…

力扣(leetcode)题目总结——辅助栈篇

leetcode 经典题分类 链表数组字符串哈希表二分法双指针滑动窗口递归/回溯动态规划二叉树辅助栈 本系列专栏&#xff1a;点击进入 leetcode题目分类 关注走一波 前言&#xff1a;本系列文章初衷是为了按类别整理出力扣&#xff08;leetcode&#xff09;最经典题目&#xff0c…

unity老猿随笔

下面是我最近开始整理的一些unity的基础知识和疑难杂症&#xff0c;如果大家有什么可以分享出来的经验&#xff0c;可以评论区留言&#xff0c;验证后整理进来&#xff0c;全猿学习&#xff01;如果有不对的地方&#xff0c;也欢迎指正&#xff0c;避免误人子弟&#xff01; l…

『VUE』30. 生命周期的介绍(详细图文注释)

目录 生命周期生命周期的8阶段生命周期小例子总结 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 生命周期 每个 Vue 组件实例在创建时都需要经历一系列的初始化步骤&#xff0c;比如设置好数据侦听&#xff0c;编译模板&#xf…

Go语言跨平台桌面应用开发新纪元:LCL、CEF与Webview全解析

开篇寄语 在Go语言的广阔生态中&#xff0c;桌面应用开发一直是一个备受关注的领域。今天&#xff0c;我将为大家介绍三款基于Go语言的跨平台桌面应用开发框架——LCL、CEF与Webview&#xff0c;它们分别拥有独特的魅力和广泛的应用场景。通过这三款框架&#xff0c;你将能够轻…

华为HCCDA云技术认证--网络服务

大家好呀&#xff01;我是reload。今天继续带大家学习华为HCCDA云技术认证&#xff0c;涵盖华为云最为核心的计算、存储、网络、数据库、安全、部署等服务。今天学习网络服务相关内容。 登录华为云官网&#xff1a;https://www.huaweicloud.com/ &#xff0c;进入首页&#xff…

rocketmq5源码系列--(一)--搭建调试环境

说在前头&#xff1a;阿里的rocketmq的文档是真他妈的烂的1b&#xff0c;很多东西都不说&#xff0c;全靠自己看源码&#xff0c;摸索&#xff0c;草&#xff0c;真的要吐血了 rocketmq的版本5而不是版本4&#xff0c;版本5比版本4多了个proxy rocketmq5 三个组件&#xff1a;…

如何通过电脑监控软件远程监控一台电脑的所有屏幕画面记录

7-1 本教程介绍一个简单的工具&#xff0c;可以安装在电脑中&#xff0c;按设置的时间间隔&#xff0c;自动对屏幕截图保存&#xff0c;并且可以在有网络的其它电脑上远程提取截图文件。 该软件用于自动记录电脑的屏幕画面内容和变化&#xff0c;如果你有这方面的使用场景&am…

Redis 概 述 和 安 装

安 装 r e d i s: 1. 下 载 r e dis h t t p s : / / d o w n l o a d . r e d i s . i o / r e l e a s e s / 2. 将 redis 安装包拷贝到 /opt/ 目录 3. 解压 tar -zvxf redis-6.2.1.tar.gz 4. 安装gcc yum install gcc 5. 进入目录 cd redis-6.2.1 6. 编译 make …

Spring Boot汽车资讯:科技与汽车的新篇章

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了汽车资讯网站的开发全过程。通过分析汽车资讯网站管理的不足&#xff0c;创建了一个计算机管理汽车资讯网站的方案。文章介绍了汽车资讯网站的系统分析部分&…

CSS:高级寄巧

精灵图 为什么需要精灵图呢&#xff1f; 一个网页中往往会应用很多小背景图作为修饰&#xff0c;当网页中的图像过多时&#xff0c;服务器就会频繁地接收和发送 请求图片&#xff0c;造成服务器请求压力过大&#xff0c;这将大大降低页面的加载速度。 因此&#xff0c;为了有…

【原创】如何备份和还原Ubuntu系统,非常详细!!

前言 我在虚拟机装了一个xfce4的Ubuntu桌面版&#xff0c;外加输入法、IDEA等&#xff0c;我想将这个虚拟机里的系统直接搬到物理机中&#xff0c;那我可以省的再重新装一遍、配置xfce4桌面、修改一堆快捷键还有配置idea了&#xff0c;那直接说干就干。 本教程基于Ubuntu24.0…

SAM_Med2D 训练完成后boxes_prompt没有生成mask的问题

之前对着这这篇文章去微调SAM_Med2D(windows环境),发现boxes_prompt空空如也。查找了好长时间问题SAM-Med2D 大模型学习笔记&#xff08;续&#xff09;&#xff1a;训练自己数据集_sam训练自己数据集-CSDN博客 今天在看label2image_test.json文件的时候发现了一些端倪: 官方…

数据结构-二叉搜索树(Java语言)

目录 1.概念 2.查找search 3.插入insert ​编辑4.删除remove&#xff08;难点&#xff09; 5.性能分析 1.概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树 : 1.若它的左子树不为空&#xff0c;则左子树上所有节点的值都…

【蓝桥杯备赛】深秋的苹果

# 4.1.1. 题目解析 要求某个区间内的数字两两相乘的总和想到前缀和&#xff0c;但是这题重点在于两两相乘先硬算&#xff0c;找找规律&#xff1a; 比如要算这串数字的两两相乘的积之和&#xff1a; 1, 2, 3 1*2 1*3 2*3 1*(23) 2*3 前缀和数组&#xff1a; 1 3 6 发现…

go-zero(一) 介绍和使用

go-zero 介绍和使用 一、什么是 go-zero&#xff1f; go-zero 是一个基于 Go 语言的微服务框架&#xff0c;提供了高效、简单并易于扩展的 API 设计和开发模式。它主要目的是为开发者提供一种简单的方式来构建和管理云原生应用。 1.go-zero 的核心特性 高性能&#xff1a; g…

3. Sharding-Jdbc核⼼流 程+多种分⽚策略

1. Sharding-Jdbc 分库分表执⾏核⼼流程 Sharding-JDBC执行流程 1. SQL解析 -> SQL优化 -> SQL路由 -> SQL改写 -> SQL执⾏-> 结果归并 ->返回结果简写为&#xff1a;解析->路由->改写->执⾏->结果归并1.1 SQL解析 1. SQL解析过程分为词法解析…