c++11线程使用(代码片段)

Jason_Lee155 Jason_Lee155     2022-12-16     714

关键词:

线程概念

C++11引入了thread类,大大降低了多线程使用的复杂度,原先使用多线程只能用系统的API,无法解决跨平台问题,一套代码平台移植,对应多线程代码也必须要修改。现在在C++11中只需使用语言层面的thread可以解决这个问题。
所需头文件:

#include <thread>

构造函数

1.默认构造函数

thread() noexcept//不会产生异常

一个空的std::thread执行对象

2.初始化构造函数

template<class Fn, class... Args>
explicit thread(Fn&& fn, Args&&... args);

创建std::thread执行对象,线程调用threadFun函数,函数参数为args。

void threadFun(int a)

    cout << "this is thread fun !" << endl;

thread t1(threadFun, 2);

3.拷贝构造函数

thread(const thread&) = delete;

拷贝构造函数被禁用,std::thread对象不可拷贝构造。

void threadFun(int& a)

    cout << "this is thread fun !" << endl;

int value = 2;
thread t1(threadFun, std::ref(value));

4.Move构造函数

thread(thread&& x)noexcept

调用成功原来x不再是std::thread对象

void threadFun(int& a)

    cout << "this is thread fun !" << endl;

int value = 2;
thread t1(threadFun, std::ref(value));
thread t2(std::move(t1));
t2.join();

成员函数

get_id()
获取线程ID,返回类型std::thread::id对象。

thread t1(threadFun);
thread::id threadId = t1.get_id();
cout << "线程ID:" << threadId << endl;
//threadId转换成整形值,所需头文件<sstream>
ostringstream   oss;
oss << t1.get_id();
string strId = oss.str();
unsigned long long tid = stoull(strId);
cout << "线程ID:" << tid << endl;

join()
创建线程执行线程函数,调用该函数会阻塞当前线程,直到线程执行完join才返回。

thread t1(threadFun);
t1.join()  //阻塞等待

detach()
detach调用之后,目标线程就成为了守护线程,驻留后台运行,与之关联的std::thread对象失去对目标线程的关联,无法再通过std::thread对象取得该线程的控制权。

swap()
交换两个线程对象

thread t1(threadFun1);
thread t2(threadFun2);
cout << "线程1的ID:" << t1.get_id() << endl;
cout << "线程2的ID:" << t2.get_id() << endl;
t1.swap(t2);
cout << "线程1的ID:" << t1.get_id() << endl;
cout << "线程2的ID:" << t2.get_id() << endl;

hardware_concurrency()
获得逻辑处理器储量,返回值为int型

int coreNum = thread::hardware_concurrency();

使用

1.创建线程

void threadFun1()

    cout << "this is thread fun1 !" << endl;


int main()

    thread t1(threadFun1);
    t1.join();

    getchar();
    return 1;

2.创建线程,传参

void threadFun1(int v)

    cout << "this is thread fun1 !" << endl;
    cout << v << endl;


int main()

    int value = 6;
    thread t1(threadFun1, value);
    t1.join();

    getchar();
    return 1;

需要注意,变量int value 和int v 做变量传递时并不是引用,而是对变量做了拷贝,所以在传递给int v前,int value不能出作用域(释放了内存),join(),可以保证int value变量释放内存,如果使用detach(),可能存在这种情况。

3.创建线程,引用传参

void threadFun1(int& v)

    cout << "this is thread fun1 !" << endl;
    cout << v << endl;


int main()

    int value = 6;
    thread t1(threadFun1, std::ref(value));
    t1.join();

    getchar();
    return 1;

//std::ref和std::cref
//解释
//std::ref 用于包装按引用传递的值。
//std::cref 用于包装按const引用传递的值。

4.创建建线程,线程函数为类成员函数

class Object

public:
    Object()
    
        cout << "构造函数" << endl;
    

    ~Object()
    
        cout << "析构函数" << endl;
    

    void fun(string info)
    
        cout << info << endl;
    
;

int main()

    Object obj;
    string str = "我是一个类的成员函数!";
    thread t1(&Object::fun, &obj, str);
    t1.join();

    getchar();
    return 1;

线程创建详解

用一个初始函数创建一个线程

直接看代码:注意c++在运行一个可执行程序的时候(创建了一个进程),会自动的创建一个主线程,这个主线程和进程同生共死,主线程结束,进程也就结束了。

#include "pch.h"
#include <iostream>
#include<thread>
void print1()

    cout << "print1_1线程执行" << endl;
    cout << "print1_2线程执行" << endl;
    cout << "print1_3线程执行" << endl;

using namespace std;
int main()

    thread mythread1(print1);
    mythread1.join();
    //mythread1.detach();
    cout << "主线程执行" << endl;
    return 0;

thread mythread1(print1)创建一个线程mythread1,print1()是该线程的初始函数(执行函数)。

mythread1.join();阻塞主线程,等待mythread1这个线程执行完毕在继续执行,推荐这种做法。
mythread1.detach();分离,使主线程和线程mythread1分离,主线程可以先执行结束,如果主线程执行完了,子线程会在c++后台运行,一旦使用detach(),与这个子线程关联的对象会失去对这个主线程的关联,此时这个子线程会驻留在c++后台运行,当主线程执行完毕结束,子线程会移交给c++运行时库管理,这个运行时库会清理与这个线程相关的资源(守护线程),detach()会是子线程失去进程的控制,所以建议不要使用detach(),建议使用jion()。

return 0;表示主线程执行完毕,表明进程即将退出。

用类对象创建一个线程

#include "pch.h"
#include <iostream>
#include<thread>
class T

public:
    /*情况一:
    int &it;//一个进程中的所有线程共享同一块内存(内存共享),在线程中使用引用其实是不安全的
    T(int &m_it) :it(m_it)
    
        cout << "构造函数被执行" << endl;
    
    */
    //不能用引用,应该像下面这样用
    int it;
    T(int m_it) :it(m_it)
    
        cout << "构造函数被执行" << endl;
    
    T(const T &t) :it(t.it) 
        cout << "拷贝构造函数被执行" << endl;
    
    ~T()
    
        cout << "析构函数被执行" << endl;
    
    void operator()()
    
        cout << "it值:" << it << endl;
    
;

int main()

    int itm = 8;
    T t(itm);//调用了构造函数
    thread mythread2(t);
    mythread2.join();
    //mythread2.detach();
    cout << "主线程执行" << endl;
    return 0;

thread mythread2(t);调用了拷贝构造函数

mythread2.detach();情况一的时候,这里绝对不能用detach(),因为类成员变量是一个引用,这里的itm等主线程执行完毕之后内存会回收,所以子线程打印的变量无效,这是一个重大的bug。一定要注意,最安全的做法就是直接使用值传递,生成一个副本,这样使用detach()就不会有错。

这里还有一个疑问?为什么使用detach(),主线程执行结束之后,用t这个局部对象没有问题,t按理说会被系统回收之后就有问题了呀?
答:虽然t这个对象不在了(肯定会被回收),但是创建子线程的时候,这个对象t是被拷贝到子线程中去了的,所以用detach()而且主线程执行完毕后,子线程还是会继续执行,这是没有问题的.t被销毁,但是被复制到线程中去的对象依然存在。

用lambda表达式创建一个线程

#include <iostream>
#include<thread>
using namespace std;
int main()

    //用lambda表达式创建一个线程
    auto mylamthread = [] //这是一个lambda表达式
        cout << "我的线程开始执行了" << endl;
        //......
        cout << "我的线程执行结束了" << endl;
    ;
    thread mythread3(mylamthread);
    mythread3.join();
    cout << "主线程执行结束" << endl;
    return 0;//表示主线程执行结束,表明进程结束

认识一个函数

joinable(),这个函数用来判断是否还可以使用join()和detach(),如果已经使用了join()或者detach(),则不能再使用detach()或者join()函数了,会返回一个布尔true,反之,返回一个false.

c++11thread学习笔记(代码片段)

C++11线程学习笔记C++11中创建线程的方式在c++11中有三种创建线程的方式:函数指针方式函数对象方式Lambda函数创建函数对象之前,首先需要引入线程的头文件,如果你是在linux下VSCode中使用线程,需要在tasks.json文件... 查看详情

c++11中多线程例子(代码片段)

C++11开始自带线程相关的操作库。这里举个例子,以并发编程最经典的例子,生产者消费者的例子来示例在C++11使用标准库提供的线程库来进行并发编程。这里为了方便线程的使用,参考了android源码中对pth... 查看详情

c/c++c++11初探多线程(代码片段)

...很多参考该专栏之前在Linux下,一直使用Pthread使用多线程变成。C++11新标准中引入了五个头文件来支持多线程编程,他们分别是<atomic>, <thread>, <mutex>, < 查看详情

c++线程的使用(代码片段)

...发程序时,存在诸多的不便。现在C++11中增加了线程以及线程相关的类,很方便地支持了并发编程,使得编写的多线程程序的可移植性得到了很大的提高。C++11中提供的线程类叫做std:: 查看详情

c++11线程池的实现原理及回调函数的使用(代码片段)

关于线程池简单来说就是有一堆已经创建好的线程(最大数目一定),初始时他们都处于空闲状态。当有新的任务进来,从线程池中取出一个空闲的线程处理任务然后当任务处理完成之后,该线程被重新放回... 查看详情

[c++11多线程同步]---互斥锁(代码片段)

1四种互斥锁在C++11中一共提供了四种互斥锁:std::mutex:独占的互斥锁,不能递归使用std::timed_mutex:带超时的独占互斥锁,不能递归使用std::recursive_mutex:递归互斥锁,不带超时功能std::recursive_timed_mutex:带超时的递归互斥锁互斥... 查看详情

[c++11多线程同步]---条件变量(代码片段)

...的时候,它使用std::unique_lock(通过std::mutex)来锁住当前线程。当前线程会一直被阻塞,直到另外一个线程在相同的std::condition_variable对象上调用了notification函数来唤醒当前线程。st 查看详情

[c++11多线程同步]---条件变量(代码片段)

...的时候,它使用std::unique_lock(通过std::mutex)来锁住当前线程。当前线程会一直被阻塞,直到另外一个线程在相同的std::condition_variable对象上调用了notification函数来唤醒当前线程。st 查看详情

[c++11多线程同步]---互斥锁(代码片段)

1四种互斥锁在C++11中一共提供了四种互斥锁:std::mutex:独占的互斥锁,不能递归使用std::timed_mutex:带超时的独占互斥锁,不能递归使用std::recursive_mutex:递归互斥锁,不带超时功能std::recursive_time... 查看详情

c++11——线程库,互斥量,原子性库,条件变量(代码片段)

目录前言一.线程库    1.线程库接口        2.使用     2.1线程函数    2.2线程函数的参数     2.3join和detach介绍二.互斥量介绍    1.互斥量种类   1.mutex最基本Mutex类    2.recursive_mutex递归Mutex类    3.timed_mutex定... 查看详情

[c/c++11]_[初级]_[获取cpu支持的最合适的核心线程数](代码片段)

场景当使用线程池时,一般需要获取最合适的最大线程数,因为在每个进程每个CPU核心最高性能是只处理一个线程。因此可见最合适的线程总数就是CPU核心数。那么如何获取CPU核心数?说明很遗憾,C++标准还没有线程池,要么自... 查看详情

[多线程]c++11多线程用法整理(代码片段)

...入了<thread>头文件,此头文件主要声明了std::thread线程类。C++11的标准类std::thread对线程进行了封装,定义了C++11标准中的一些表示线程的类、用于互斥访问的类与方法等。应用C++11中的std::thread便于多... 查看详情

c++线程的使用(代码片段)

...发程序时,存在诸多的不便。现在C++11中增加了线程以及线程相关的类,很方便地支持了并发编程,使得编写的多线 查看详情

c++11thread学习笔记(代码片段)

C++11线程学习笔记C++11中创建线程的方式在c++11中有三种创建线程的方式:函数指针方式函数对象方式Lambda函数创建函数对象之前,首先需要引入线程的头文件,如果你是在linux下VSCode中使用线程,需要在tasks.json文件... 查看详情

[c++11多线程异步]---std::promise/std::future(代码片段)

1为什么需要异步C++11中增加的线程类,使得我们能够非常方便的创建和使用线程,但有时会有些不方便,比如需要获取线程返回的结果,就不能通过join()得到结果,只能通过一些额外手段获得,下面给出具体实现代码:#include<... 查看详情

[c/c++11]_[初级]_[获取cpu支持的最合适的核心线程数](代码片段)

场景当使用线程池时,一般需要获取最合适的最大线程数,因为在每个进程每个CPU核心最高性能是只处理一个线程。因此可见最合适的线程总数就是CPU核心数。那么如何获取CPU核心数?说明很遗憾,C++标准还没有线程池,要么自... 查看详情

c++11多线程编程之线程类(代码片段)

...发程序时,存在诸多的不便。现在C++11中增加了线程以及线程相关的类,很方便地支持了并发编程,使得编写的多线程程序的可移植性得到了很大的提高。C++11中提供的线程类叫做std:: 查看详情

c++11中多线程例子(代码片段)

C++11开始自带线程相关的操作库。这里举个例子,以并发编程最经典的例子,生产者消费者的例子来示例在C++11使用标准库提供的线程库来进行并发编程。这里为了方便线程的使用,参考了android源码中对pth... 查看详情