首页 > 编程语言 >C++ 多线程并发

C++ 多线程并发

时间:2023-04-25 23:55:57浏览次数:54  
标签:std include int lock C++ 并发 task 线程 多线程

C++ 参考手册 - 并发支持库

《C++ Concurrency in Action》

https://segmentfault.com/a/1190000040628584?utm_source=sf-similar-article

https://zhuanlan.zhihu.com/p/547312117

bilibili C++ 多线程并发 基础入门教程

1 创建线程

C++11 之前原生不支持多线程,C++11起逐步引入了对线程的支持。

std::thread<thread> 头文件中声明,因此使用 std::thread 时需要包含 <thread> 头文件。

#include <iostream>
#include <thread>

void func(int a) {
    while (true) {
        std::cout << "hello world" << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(50));  // 休眠50毫秒
    }
}
int main() {
    int n = 0;
    std::thread t1(func, n);
    return 0;
}

上述代码中我们创建了一个 thread 线程 t1, 让它调用函数 func,并为其传入函数参数 n。

❗️线程创建后即开始运行,不需要调用 run 之类的函数才能执行。

但我们发现程序运行没多久,就会报错,这是因为主线程 main 创建完子线程 t1 后没有任何代码,就退出了。而子线程 t1 还没有执行完毕,此时就会报错了。

解决方法:

1️⃣ 使用 join 函数

这样主线程 main 即使执行完成,也会一直等待 join 的子线程执行完毕,才会结束。

...
int main() {
    int n = 0;
    std::thread t1(func, n);
    t1.join();
    return 0;
}

2️⃣ 使用 detach 函数

该函数会将主线程和子线程完全分离开,二者不再有任何关系。主线程 main 创建完子线程 t1 后,执行后续代码,执行完毕就直接退出。

...
int main() {
    int n = 0;
    std::thread t1(func, n);
    t1.detach();
    return 0;
}

detach其实就是一个守护线程。

使用 detach() 时要注意访问数据的有效性,假如向子线程 t1 传入的参数是个指针/引用,在主线程 main 执行完毕退出后,指针指向的内容就会失效,而子线程中还在使用该指针,则会出现错误。

线程的入口函数 可以是:普通函数、类的静态/非静态成员函数、lambda 表达式。

1.1 其他操作

操作 功能 示例
swap(std::thread& other) 交换两个线程 std::thread t1(func, n);
std::thread t2(func, n);
t1.swap(t2);
get_id() 返回线程 id t1.get_id();
hardware_concurrency() 返回硬件所实现支持最大并发线程数
(值不一定准确,只能做参考)
t1.hardware_concurrency();
native_handle() 返回操作系统支持的线程句柄 t1.native_handle();

这些都是在创建子线程 t1 的主线程 main 中能操作的方法,若我要在子线程 t1 执行的函数 func 中获取这些数据,要如何调用?使用 std::this_thread 操作当前线程。

#include <iostream>
#include <thread>

void func(int a) {
    while (true) {
        std::cout << "thread_id = " << std::this_thread::get_id() << std::endl;
        std::cout << "hardware_concurrency = " << std::this_thread::hardware_concurrency() << std::endl;
        std::cout << "native_handle = " << std::this_thread::native_handle() << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(50));  // 休眠50毫秒
    }
}
int main() {
    int n = 0;
    std::thread t1(func, n);
    return 0;
}

std::this_thread 还有其他的方法:

操作 功能 示例
sleep_for() 睡眠一段时间 std::this_thread::sleep_for (std::chrono::seconds(1));
sleep_until() 睡眠到一个绝对时间
yield() 当前线程放弃执行
操作系统调用另一线程继续执行
while (!ready) { // wait until main() sets ready...
std::this_thread::yield();
}

2 互斥量(mutex)

2.1 基础使用

#include <iostream>
#include <thread>

int global_veriable = 0;
void task() {
    for (int i = 0; i < 1000; i++) {
        global_veriable++;
        global_veriable--;
    }
}
int main() {
    std::thread t1(task);
    std::thread t2(task);
    t1.join();
    t2.join();
    std::cout << "current value is " << global_veriable;
    return 0;
}

看代码感觉 global_veritable 应该为 0,但是实际上可能每次运行都是不同的值。因为两个线程都会对该公共变量 global_veritable 进行读写访问。

多线程编程需考虑对公共资源的保护,否则涉及对公共资源访问的代码是不安全的。—— 互斥量(mutex)

std::mutex 对象提供了独占所有权的特性。在 <mutex> 头文件中声明,因此使用 std::mutex 时需要包含<mutex> 头文件。

现在,我们在

标签:std,include,int,lock,C++,并发,task,线程,多线程
From: https://www.cnblogs.com/angelia-wang/p/17354385.html

相关文章

  • oracle 最大并发数 会话数查询
    怎样查看oracle当前的连接数SQL>selectcount(*)fromv$session#当前的连接数SQL>Selectcount(*)fromv$sessionwherestatus='ACTIVE'#并发连接数SQL>selectvaluefromv$parameterwherename='processes'--数据库允许的最大连接数SQL>showparameterpro......
  • 用Winsock编写服务端和客户端 (C++)
      在这里先向大家推荐一本不错的入门书籍——《TCPIP网络编程》(尹圣雨著),这本书比较贴近实战,是一本不错的网络编程方向的指导用书。如果需要PDF版本,可以后台私信我! 回归正题,我们欲要使用C++实现一个简易的服务端和客户端控制台程序。代码如下:  服务端:/***************......
  • Rust编程语言入门之最后的项目:多线程 Web 服务器
    最后的项目:多线程Web服务器构建多线程Web服务器在socket上监听TCP连接解析少量的HTTP请求创建一个合适的HTTP响应使用线程池改进服务器的吞吐量优雅的停机和清理注意:并不是最佳实践创建项目~/rust➜cargonewhelloCreatedbinary(application)`......
  • 快速掌握并发编程---深入学习ThreadLocal
    生活中的ThreadLocal考试题只有一套,老师把考试题打印出多份,发给每位考生,然后考生各自写各自的试卷。考生之间不能相互交头接耳(会当做作弊)。各自写出来的答案不会影响他人的分数。注意:考试题、考生、试卷。用代码来实现:publicclassThreadLocalDemo{//线程共享变量localVar......
  • C++第四章课后习题4-12
    定义一个datatype类,能处理包含字符型,整形,浮点型3种类型的数据,给出其构造函数。1#include<iostream>2usingnamespacestd;34classDataType{5private:6chara;7intn;8floatx;9enum{10character,11intege......
  • PTA1004 成绩排名(C++)
    一、问题描述:读入 n(>0)名学生的姓名、学号、成绩,分别输出成绩最高和成绩最低学生的姓名和学号。输入格式:每个测试输入包含1个测试用例,格式为第1行:正整数n第2行:第1个学生的姓名学号成绩第3行:第2个学生的姓名学号成绩.........第n+1行:第n个学生的......
  • jdk并发包 CopyOnWriteArrayList源码分析
    CopyOnWriteArrayList是jdk1.5并法包里面用于处理高并发下,读多写少的情况下,降低锁等待的集合类。下面对该类实现做一个简要的分析1,首先CopyOnWriteArrayList是实现了List接口,对=List接口的相关方法进行了实现。2,下面的它的add方法,会首先加锁,然后copy原List内部的数组,然后对新数组长......
  • c++打卡第十五天
    一、问题描述 二、设计思路。①、我们在此使用结构体定义结构体数组,结构体数组中包括每个阶段的征税始末,以及相对应的税率。当我们将工资传入时,会出现相应阶段的部分,以及总共应需缴纳金额。②、我们设计计算函数,通过for循环进行计算各个阶段的计算,同时使用选择语句,判断工资是......
  • C++每日打卡
    计算年龄问题定义一个Birthday类,其成员变量有3个整形变量(出生的年月日):year,month,day;提供构造方法对这3个成员变量进行初始化;成员函数有getAge(),其功能是实现计算到2017年12月25日时该Birthday对象的年龄。 #include<iostream>usingnamespacestd;classBirthday{int......
  • C++基础3: 引用
    前言本篇首先回顾指针的概念,用C指针的缺陷引出C++中的引用,然后对引用进行说明比如,什么是引用?引用解决指针什么问题?引用的特性和使用等等1.指针什么是指针指针是内存单元的地址,口语中的指针实际上是指针变量,存储地址的变量#include<stdio.h>intmain(){ i......