c++多线程(一)初识多线程

本文介绍了C++11中的多线程基础知识,包括线程创建、线程安全等概念,并详细讲解了如何使用C++11提供的标准库进行多线程编程,如std::thread的使用方法及注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、基础知识

  • 多线程:指的是这个程序(一个进程)运行时产生了不止一个线程
  • 并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。
  • 并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。
  • 线程安全:经常用来描绘一段代码。指在并发的情况之下,该代码经过多线程使用,线程的调度顺序不影响任何结果。这个时候使用多线程,我们只需要关注系统的内存,cpu是不是够用即可。反过来,线程不安全就意味着线程的调度顺序会影响最终结果。
  • 同步:通过人为的控制和调度,保证共享资源的多线程访问成为线程安全,来保证结果的准确。

二、相关库

C++标准并没有提供对多进程并发的原生支持,所以C++的多进程并发要靠其他API——这需要依赖相关平台。

C++11 标准提供了一个新的线程库,内容包括了管理线程、保护共享数据、线程间的同步操作、低级原子操作等各种类。标准极大地提高了程序的可移植性,以前的多线程依赖于具体的平台,而现在有了统一的接口进行实现。

这里是windows下的c++多线程,Linux下的头文件会有区别。

C++11 新标准中引入了几个头文件来支持多线程编程:

  • 1、 < thread > :包含std::thread类以及std::this_thread命名空间。管理线程的函数和类在 中声明.
  • 2、 < atomic > :包含std::atomic和std::atomic_flag类,以及一套C风格的原子类型和与C兼容的原子操作的函数。
  • 3、 < mutex > :包含了与互斥量相关的类以及其他类型和函数
  • 4、 < future > :包含两个Provider类(std::promise和std::package_task)和两个Future类(std::future和std::shared_future)以及相关的类型和函数。
  • 5、 < condition_variable > :包含与条件变量相关的类,包括std::condition_variable和std::condition_variable_any。

三、初试多线程

完整示例见github

3.1 线程的创建

用std::thread 创建线程非常的简单,只需要提供线程函数或者函数对象即可,并可以同时指定线程的参数:

#include "stdafx.h"
#include "ThreadLearning.h"

void print_hello()
{
    cout << "hello world" << endl;
}

void print(string str)
{
    cout << str << endl;
}

void hello_world()
{
    string tmp;

    //这是不带参数的调用
    //创建线程对象t1,绑定线程函数为hello
    thread t1(print_hello);
    //输出t1的线程ID
    std::cout << "ID:" << t1.get_id() << std::endl;
    //等待t1线程函数执行结束
    //join函数将会阻塞线程,直到线程函数执行结束,如果线程函数有返回值,返回值将被忽略.
    t1.join();

    //带参数的调用
    //创建线程对象ta,绑定线程函数为print
    tmp = "A";
    thread ta(print, tmp);
    ta.join();
    tmp = "B";
    thread tb(print, tmp);
    tb.join();
    tmp = "C";
    thread tc(print, tmp);
    tc.join();
}

int main()
{
    hello_world();
    return 0;
}
  • 线程函数将会运行于线程对象t中,join函数将会阻塞线程,直到线程函数执行结束,如果线程函数有返回值,返回值将被忽略.

  • detach可以将线程与线程对象分离,让线程作为后台线程执行,当前线程也不会阻塞了.但是detach之后就无法在和线程发生联系了.如果线程执行函数使用了临时变量可能会出现问,线程调用了detach在后台运行,临时变量可能已经销毁,那么线程会访问已经被销毁的变量.

  • 虽然这种方式创建线程很方便,但是std::thread 出了作用域后将会析构,这个时候线程函数还没执行完则会发生错误

3.2 线程移动

线程不可以复制但是可以移动.但是线程移动后,线程对象将不再代表任何线程了

void thread_move()
{
    std::thread t(func, 2, 3, 4);
    //移动后,线程对象t不在代表任何线程
    std::thread t1(std::move(t));
    //t.join();
    t1.join();
}

move后,t的值如下所示:

t = {_Thr={_Hnd=0x00000000 _Id=0 } }
如果继续调用t.join(),会引发异常,因为t不代表任何线程

参考文献

1、多线程编程基础知识
2、C++11多线程基本使用
3、C++ 11 Threads: Make your (multitasking) life easier.
4、C++11 线程:让你的多线程任务更轻松

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值