返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++初级线程使用方法有哪些
  • 372
分享到

C++初级线程使用方法有哪些

2023-06-22 05:06:44 372人浏览 独家记忆
摘要

这篇文章主要讲解了“c++初级线程使用方法有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++初级线程使用方法有哪些”吧!1 线程启动C++11中,线程的启动终究是对std::thre

这篇文章主要讲解了“c++初级线程使用方法有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++初级线程使用方法有哪些”吧!

1 线程启动

C++11中,线程的启动终究是对std::thread的对象进行构造。

线程构造的类别如下:

1.1  线程函数无参数无返回值

此类可以说是最简单的线程启动,函数不需要传参也不需要返回函数执行结果,执行完成后,线程自动退出。

形如:

void FunDoingNothing();std::thread(FunDoingNothing)

编写代码时,需要加上<thread>头文件以方便编译器能够正确处理thread对象。

1.2  线程函数有参数无返回值

C+=11中,thread的构造函数中使用了可变参数,这样,可以使得构造thread对象时可以自定义传入参数,

构造函数的定义如下:

template<class F, class... Args> explicit thread(F&& f, Args&&... args);

在实际使用时,线程函数有参数时可以定义形式如下:

void printMsg(int a, int b) {  cout << "input params are:" << a <<","<<b<< endl;}std::thread my_thread(printMsg, 3, 4)

1.3  调用可调用的类型构造

使用时,可以将带有执行函数的变量传入thread的构造函数中从而替换默认的构造函数,

如下:

using namespace std;class BackGroundTask{ public:    void operator()() const{        doSomeThing();    }priavte:    doSomeThing();};int main(){    BackGroundTask f;    std::thread myThread(f);}

上面的代码中,在启动线程时同构构造对象f,f对象的重载函数中调用了线程运行时要执行的方法。但有一点需要注意的是,在传入临时的构造对象时,不经过处理,可能会让编译器产生错误的理解。

如:

std::thread myThread(BackGroundTask());

这里相当与声明了一个名为myTread的函数, 这个函数带有一个参数(函数指针指向没有参数并返回BackGroundTask对象的函数), 返回一个 std::thread 对象的函数, 而非启动了一个线程。

如果要解决这个问题,只需要如下处理即可:

std::thread myThread((BackGroundTask()));std::thread myThread{BackGroundTask()};

当然,也可以使用lamda表达式实现上述功能,如下:

std::thread myThread([]{  doSomeThing();  });

2 等待线程

C++11中,确保线程执行完后,主线程在退出,需要在代码中使用join()函数,这样就可以保证变量在线程结束时才会进行销毁。

2.1 join等待

在实际编程时,join函数只是简单的等待或者不等待。在有些场景下就会不使用,如果想要进行更加灵活的控制,需要使用C++11中提供的其他机制,这个也会在后面的推文中进行说明。
在编程时,如果对一个线程使用了join,那么在后续的操作中如果使用joinable()执行结果将返回false。既一旦使用了join。线程对象将不能重复使用。如下代码中,在线程中使用join等待。

class BackGroundTask{ public:    void operator()(){        doSomeThing();    } private:    void doSomeThing() {cout<<"线程退出"<<endl;};};int main(){    BackGroundTask f;    std::thread myThread(f);    myThread.join();    cout<<"退出"<<endl;}

上面的代码使用了线程等待,可以输出正确的结果,如下:

线程退出
退出

如果将 myThread.join()语句注释,再次执行时,程序将执行出错,因为在子线程还没有结束时,主线程已经结束。

运行结果如下:

退出
terminate called without an active exception

上面的输出具备不确定性,代码运行时结果随机。

2.2 异常场景的join等待

异常场景中,如果没有充分考虑join的位置,就可能会产生因为异常导致主线程先于子线程退出的情况,解决这些问题可以通过下面两种方法进行处理:

2.2.1  通过异常捕获

通过分析代码中的异常场景,对异常使用try...catch进行捕获,然后在需要线程等待的地方调用join()函数,这种方法虽然可以轻易地捕获问题并对问题进行修复,但并非是通用法则,还需要根据实际情况进行分析。如检查并确认是否线程函数中是否使用了局部变量的引用等其它原因。

2.2.2 使用RAII方式进行线程等待

RAII可以理解为资源获取既初始化。因为全写为:Resource Acquisition Is Initialization
实际使用时,通过定义一个类,然后在析构函数中使用join函数进行线程等待。这样可以避免场景有遗漏的地方。

class thread_guard{private:    std::thread& t;public:    explicit thread_guard(std::thread& t_):t(t_){}    ~thread_guard()    {        if(t.joinable())        {            t.join();        }    }     thread_guard(thread_guard const&)=delete;    thread_guard& operator=(thread_guard const&)=delete;};

 如上,通过在将线程对象传入到类thread_guard中,如果thread_guard类对象的局部变量被销毁,则在析构函数中会将线程托管到原始线程。
thread_guard中,使用delete标识,禁止生成该类的默认拷贝构造、以及赋值函数。
在实际编程时如果不想线程等待,可以使用detach方法,将线程和主线程进行分离。

3 线程分离

线程分离使用detach方法,使用后将不能在对已分离的线程进行管理,但是分离的线程可以真实的在后台进行运行。当线程退出时,C++会对线程资源进行清理和回收。
线程分离通常被用作守护线程或者后台工作线程。

使用方法如下:

int main(){    BackGroundTask f;    std::thread myThread(f);    myThread.detach();    cout<<"退出"<<endl;}

4 向线程传递参数

向线程传递参数非常简单,在上面的代码中也有提及,这里主要说下向线程中传递参数的陷阱。

看下面的代码:

void f(int i,std::string const& s);void oops(int some_param){char buffer[1024]; sprintf(buffer, "%i",some_param);std::thread t(f,3,buffer);t.detach();}

上面的代码中buffer是一个局部指针变量,使用后,可能会导致线程出现未定义的行为,因为从char*到string的转换时使用的是隐式转换,但是thread在使用时会将变量拷贝到线程私有内存,但是并不知道需要将参数进行转换,因此复制到私有内存的变量就没有转换成期望的对象。
如果要解决这个问题,可以在使用时直接将参数类型转换成函数默认的类型,在上面的例子中可以

做如下操作:

std::thread t(f,3,std::string(buffer));

但是这样做依然存在问题,既线程在复制变量到私有内存时,只复制了变量值,这样在线程调用后,如果继续使用线程函数处理后的变量时可能变量并没有改造,依旧是线程调用之前的变量。
因此要想在函数传参过程中使得线程拷贝时依旧保持引用,可以在线程调用时使用引用方式,

如:

std::thread t(f,3,std::ref(std::string(buffer)));

5 线程识别

每个线程都有一个线程标识,在C++11中,线程标识通过std::thread::id进行标识,std::thread::id可以复用并进行比较,如果两个线程的id相等,那么它们就是同一个线程或者没有线程,如果不等就表示两个是不同的线程或者其中一个线程不存在。

线程id的获取方法有两种,如下:

5.1 thread成员函数获取

通过std::thread::get_id()可以获取线程的id。

使用方法如下:

int main(){    BackGroundTask f;    std::thread myThread(f);    cout<<"线程id:"<<myThread.get_id()<<endl;    myThread.detach();    cout<<"退出"<<endl;}

线程运行结果为:

  • 线程id:139879559096064

  • 退出

5.2 std::this_thread::get_id()

线程id可以用来区分主线程和子线程,通过std::this_thread::get_id()可以先将主线程id保存,然后在和子线程进行比较,从而区分主线程和子线程。

代码如下:

int main(){    std::thread::id master_thread=std::this_thread::get_id();    BackGroundTask f;    std::thread myThread(f);    if(master_thread!=myThread.get_id())    {        cout<<"子线程id:"<<myThread.get_id()<<endl;    }    myThread.detach();    cout<<"退出"<<endl;}

代码中,先保存了主线程的id标识,然后获取子线程id,比较两个线程id。如果不相等则输出子线程id。

代码运行结果如下:

子线程id:140161423791872

感谢各位的阅读,以上就是“C++初级线程使用方法有哪些”的内容了,经过本文的学习后,相信大家对C++初级线程使用方法有哪些这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

--结束END--

本文标题: C++初级线程使用方法有哪些

本文链接: https://lsjlt.com/news/302681.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • C++初级线程使用方法有哪些
    这篇文章主要讲解了“C++初级线程使用方法有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++初级线程使用方法有哪些”吧!1 线程启动C++11中,线程的启动终究是对std::thre...
    99+
    2023-06-22
  • c#使用多线程的方式有哪些
    在C#中,有多种方式可以使用多线程:1. 使用Thread类:可以通过创建Thread对象,并将一个方法或委托分配给它的Start方法来创建一个新线程。例如:```csharpThread thread = new Thread(Som...
    99+
    2023-08-09
    c#
  • java线程池使用的方法有哪些
    Java线程池使用的方法有以下几种:1. Executors类的静态方法:- newFixedThreadPool(int nThr...
    99+
    2023-08-20
    java
  • Java线程池的使用方法有哪些
    本文小编为大家详细介绍“Java线程池的使用方法有哪些”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java线程池的使用方法有哪些”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。线程池的创建⽅法总共有 7 种,但...
    99+
    2023-07-05
  • Vim高级使用方法有哪些
    这篇文章主要介绍了Vim高级使用方法有哪些的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Vim高级使用方法有哪些文章都会有所收获,下面我们一起来看看吧。你会发现,使用 Vim 非常方便的的场景几乎总是涉及到运行...
    99+
    2023-06-27
  • bash高级使用方法有哪些
    小编给大家分享一下bash高级使用方法有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!linux的发布版本之一--Redhat/CentOS--系统默认安装的...
    99+
    2023-06-27
  • c语言线程同步的方法有哪些
    C语言线程同步的方法有以下几种:1. 互斥锁(Mutex):使用互斥锁可以保证在同一时间只有一个线程能够进入关键代码段。当一个线程获...
    99+
    2023-10-12
    c语言
  • C++初始化列表的方法有哪些
    本篇内容介绍了“C++初始化列表的方法有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、类的初始化表首先是类中使用构造函数时的初始化表...
    99+
    2023-07-05
  • python使用线程的方式有哪些
    本篇内容主要讲解“python使用线程的方式有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“python使用线程的方式有哪些”吧!  Python中使用线程有两种方式:函数或者用类来包装线程...
    99+
    2023-06-02
  • Java多线程应用方法有哪些
    这篇文章主要讲解了“Java多线程应用方法有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java多线程应用方法有哪些”吧!Java多线程程序中经常用到的方法有以下几个:run(),st...
    99+
    2023-06-17
  • c语言实现多线程的方法有哪些
    C语言实现多线程的方法有以下几种:1. POSIX线程库:POSIX是一种标准接口,用于跨平台的线程编程。C语言中可以使用pthre...
    99+
    2023-08-18
    c语言
  • C++的vector使用方法有哪些
    这篇文章主要讲解了“C++的vector使用方法有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++的vector使用方法有哪些”吧!C++vector 用法整理1.头文件#inclu...
    99+
    2023-06-29
  • c#使用listbox的方法有哪些
    在C#中,可以使用ListBox控件的方法包括但不限于以下几种:1. Add方法:向ListBox中添加项。```csharplis...
    99+
    2023-08-09
    c# listbox
  • c++在线编译的方法有哪些
    有许多在线C++编译器可以用来编译和运行C++代码,以下是一些常用的在线C++编译器: Ideone:https://ideone...
    99+
    2024-03-04
    c++
  • Java多线程常用的方法有哪些
    本文小编为大家详细介绍“Java多线程常用的方法有哪些”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java多线程常用的方法有哪些”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。一、线程相关概念程序:是为完成特定...
    99+
    2023-07-04
  • C#线程操作常见的操作方法有哪些
    这篇文章主要讲解了“C#线程操作常见的操作方法有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C#线程操作常见的操作方法有哪些”吧!C#线程操作常见的操作方法是什么呢?C#线程操作方法的...
    99+
    2023-06-17
  • C++11的bitset使用方法有哪些
    本篇内容介绍了“C++11的bitset使用方法有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!构造bitset对象构造16位的b1,每...
    99+
    2023-06-19
  • C#中Volatile的使用方法有哪些
    本篇内容介绍了“C#中Volatile的使用方法有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1.Overview经常研究.NET源码...
    99+
    2023-06-25
  • c#中gdi的使用方法有哪些
    在C#中,GDI(Graphics Device Interface)用于处理图形和图像的绘制和操作。以下是一些常见的使用方法:1....
    99+
    2023-08-21
    c#
  • c++中cast的使用方法有哪些
    在C++中,有四种类型的cast,分别是static_cast、dynamic_cast、const_cast和reinterpre...
    99+
    2024-03-12
    c++
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作