您的位置:首页 > 其它

std::thread线程详解(1)

2021-01-01 21:12 155 查看

目录

  • 总结
  • Ref
  • 简介

    本文主要介绍了标准库中的线程部分。线程是目前多核编程里面最重要的一部分。
    与进程进程相比,其所需的资源更少,线程之间沟通的方法更多; 他们之间的区别可以比较简明用以下几点概括[1]:

    1. 进程是资源分配的最小单位,线程是CPU调度的最小单位;也就是说进程之间的资源是相互隔离,而线程之间的是可以相互访问的。
    2. 线程的存在依赖于进程,一个进程可以保护多个线程;
    3. 进程出现错误不会影响其他进程,但是一个线程出现错误,会影响同一进程下的所有线程。

    线程的使用

    线程的创建

    一般使用

    std::thread
    创建一个线程。
    std::thread
    支持输入一个函数对象,及一些参数,类似于
    std::bind
    ,不过没有占位符。

    最常见,最简单的是对输入一个匿名函数作为参数:

    std::thread t1([]() {
    std::cout << "Hello World" << std::endl;
    });
    t1.join();

    需要注意的是,在使用多线程的时候,如果使用类似于

    std::cout << "Hello World" << std::endl;
    的语句,容易造成输出的混乱。比如

    std::thread t1([]() {
    std::cout << "Hello World1" << std::endl;
    });
    std::thread t2([]() {
    std::cout << "Hello World2" << std::endl;
    });
    t1.join();
    t2.join();

    以上代码,我们一般来说期望的输出是

    但是,在一些情况下,它还会以以下的方法输出

    造成这个的原因很简单,因为

    "Hello World"
    std::endl
    的输出是分开的,所以他们之间可能被插入其 ad8 他的输出。为了解决这个问题。一般会使用一个完整的字符串进行输出,但是C++在格式化这一方面做的比较差(
    C++20
    format
    库看起来还不错),所以一般情况下会使用
    printf
    输出。

    线程的方法和属性

    1. joinable()
      判断线程是否可连接(可执行线程)的,有以下情况的,为不可连接的:

      构造时,
      thread()
      没有参数;
    2. 该对象的线程已经被移动了;
    3. 该线程已经被
      join
      detach
  • get_id()
    返回线程的ID;

  • native_handle()
    返回
    POSIX
    标准的线程对象;

  • join()
    等待线程执行完成;

  • detach()
    分离线程,分离后对象不再拥有线程。该线程结束后,会自动回收内存。(并不会开启另一个进程);

  • swap()
    交换对象的线程。

  • std::jthread (C++20)

    除了常用的

    std::thread
    外,标准库还存在着另一个可以创建线程的类,
    std::jthread
    。他们之间的差别比较明显的就是,
    std::jthread
    会在解构的时候判断线程是否还在运行
    joinable
    ,如果还在运行则自动调用
    request_stop
    join

    除此之外,

    std::jthread
    还提供了一个内置的
    std::stop_token
    。可以通过线程函数的第一个参数来获取(如果函数的第一个参数类型为
    std::stop_token
    )。

    可以通过

    get_stop_source
    get_stop_token
    request_stop
    等方法来对其进行操作。

    stop_token (C++20)

    stop_token
    类似于一个信号,告诉线程是否到了结束的时候。和
    stop_source
    一起使用。
    stop_token
    用来获取是否退出(读),而
    stop_source
    用来请求推出(读写)。其方法:

    1. request_stop
      请求退出

    2. stop_requested
      获取是否已经请求退出

    3. stop_possible
      获取是否可以请求退出

    样例:

    void thread_func(std::stop_token token) {
    int data = 0;
    while (!token.stop_requested()) {
    printf("%d\n", data);
    data++;
    std::this_thread::sleep_for(1s);
    }
    printf("Exit\n");
    }
    
    int main() {
    std::jthread mythread(thread_
    ad0
    func);
    
    std::this_thread::sleep_for(4s);
    
    return 0;
    }

    输出:

    总结

    本次讲述了线程创建的一些方法,可以看到相比较C语言而言,由于C++11提出的函数对象(普通函数、匿名函数,

    std::bind
    的输出等)使得线程的创建更加的方便。

    下一次将讲述线程之间的通信。在C++中,线程之间的通信方法和C语言提供的类似,不过是将其包装了一下。

    Ref

    [1] https://www.zhihu.com/question/25532384

    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: