news 2026/7/7 7:45:56

C++11线程库的使用(上)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++11线程库的使用(上)

1.线程库的基本使用

在C++11中引入了原生的线程支持,包含在<thread>头文件中,我们下面来看看该线程库的基本使用方法,先看下面这段程序。

#include <iostream> #include <thread> void show(void) { std::cout << "hello thread" << std::endl; } int main() { std::thread thread(show); std::cout << "main" << std::endl; return 0; }

我们创建了一个线程对象,将show函数作为入口传入。当我们运行时有以下运行结果:

虽然我们的hello thread成功输出出来了,但是却出现了错误,这是因为在我们子线程还没有结束时,我们的main线程已经return结束啦,就导致出现了错误。那么怎么办呢?我们来看下面这段程序:

#include <iostream> #include <thread> void show(void) { std::cout << "hello thread" << std::endl; } int main() { std::thread thread(show); std::cout << "main" << std::endl; thread.join(); return 0; }

我们再来看运行结果:

可见我们在main结束前加入了一句thread.join()就解决了这个问题,这是因为当这个调用时一个阻塞调用,主线程运行到这里后就会被阻塞,只有当子线程结束后主线程才能进行往下执行。所以就解决了上面子线程还没有结束主线程就结束了导致的报错,我们将上面的程序修改一下会有更明显得体现,如下:

#include <iostream> #include <thread> void show(void) { for (int i = 0; i < 100000; i++) { std::cout << "hello thread" << std::endl; } } int main() { std::thread thread(show); thread.join(); std::cout << "main" << std::endl; return 0; }

运行结果为:

可见mian的输出是在子线程输出完后再输出的。当然我们还可以是用另一个方法来解决上面报错问题。

#include <iostream> #include <thread> void show(void) { std::cout << "hello thread" << std::endl; } int main() { std::thread thread(show); std::cout << "main" << std::endl; thread.detach(); return 0; }

运行结果为:

我们可以看到确实没有报错了,但是我们的hellothread确没有被输出出来。这是因为当主函数运行到thread.detach时子线程和主线程分离了,子线程进入后台执行,而主线程后面就立即结束了,所以就没有输出,但是主线程结束后子线程还可以自动在后台运行。接着我们来看看当要传入参数怎么书写程序:

#include <iostream> #include <thread> #include <string> using namespace std; void show(string s) { cout << s << endl; } int main() { thread thread(show,"hello thread"); cout << "main" << endl; thread.join(); return 0; }

我们只需要在创建thread对象,传入一个所需的参数即可。看运行结果:

2.线程使用过程中的易错问题

(1)线程间传递临时变量

我们来看下面的程序:

#include <iostream> #include <thread> #include <string> using namespace std; void process(int& n) { n += 1; } int main() { int data = 1; thread thread(process,data); thread.join(); cout << "data=" << data << endl; return 0; }

我们想启用一个线程process对我们创建的data进行加1操作时用上面的程序能不能做到呢,看运行结果:

可见直接出现了错误,这是因为我们在线程间传递临时变量出现的错误,我们通过std::ref来解决该问题程序如下所示:

#include <iostream> #include <thread> #include <string> using namespace std; void process(int& n) { n += 1; } int main() { int data = 1; thread thread(process,ref(data)); thread.join(); cout << "data=" << data << endl; return 0; }

(2)传递指针和引用时指向局部变量

我们看下面这段程序:

#include <iostream> #include <thread> #include <string> using namespace std; thread t; void process(int& n) { n += 1; } void func(void) { int data = 1; t = thread(process, ref(data)); } int main() { func(); t.join(); return 0; }

我们可以知道data局部变量在func函数结束后会被释放,所以等到引用n在使用data那块空间时已经被释放了所以就会出现报错,指针也是一样的,那么怎么解决呢?我们可以将data定义为全局变量即可。

(3)类成员函数作为入口参数,类对象被提前释放

我们看下面这段程序:

#include <iostream> #include <thread> #include <string> using namespace std; class A { public: void show() { cout << "A" << endl; } }; int main() { A a; thread t(&A::show,&a); return 0; }

当线程的入口参数时类成员函数时,我们还要将类的对象的地址也作为参数传入。这里因为我们创建一个对象所以我们要进行销毁,但是销毁的时机我们却不好把握。这里如果当对象a被提前销毁了,而线程想要使用类的成员函数就会出现问题。对于这个问题我们可以使用智能指针的方法来解决。看下面的程序:

#include <iostream> #include <thread> #include <string> #include <memory> using namespace std; thread t; class A { public: void show() { cout << "A" << endl; } }; int main() { shared_ptr<A> a = make_shared<A>(); thread t(&A::show, a); t.join(); return 0; }

对于智能指针来说,当其在没有地方使用时就会自动释放掉,既不会造成内存的泄露,也能更好的让线程执行类的成员函数。

(4)使用类的私有成员函数作为线程的入口参数

对于这个问题,我们可以使用友元函数进行解决,如下:

#include <iostream> #include <thread> #include <string> #include <memory> using namespace std; thread t; class A { private: friend void func(); void show() { cout << "A" << endl; } }; void func() { shared_ptr<A> a = make_shared<A>(); thread t(&A::show, a); t.join(); } int main() { func(); return 0; }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/7 19:03:15

Mermaid Live Editor:3步掌握终极在线图表创作神器

还在为技术文档的可视化表达而烦恼吗&#xff1f;Mermaid Live Editor作为一款革命性的在线图表制作工具&#xff0c;让你通过简洁的文本语法快速生成专业级图表。这款基于React开发的实时编辑器支持流程图、序列图、甘特图等多样化图表类型&#xff0c;为系统设计、项目管理和…

作者头像 李华
网站建设 2026/7/7 7:56:36

openMES开源制造执行系统:从零部署到生产智能化的完整指南

openMES是一款基于国际ISA88和ISA95标准设计的开源制造执行系统&#xff0c;为中小企业提供数字化转型的完整解决方案。通过模块化架构和灵活配置&#xff0c;系统能够无缝对接离散制造与流程工业场景&#xff0c;实现生产过程透明化、智能化和高效化管理。 【免费下载链接】op…

作者头像 李华
网站建设 2026/7/7 18:08:53

【Java毕设全套源码+文档】基于springboot的二手家电管理平台设计与实现(丰富项目+远程调试+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/7/7 16:42:48

ComfyUI Manager节点列表获取失败的终极解决方案指南

ComfyUI Manager节点列表获取失败的终极解决方案指南 【免费下载链接】ComfyUI-Manager 项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI-Manager &#x1f6a8; 问题概述&#xff1a;在使用ComfyUI Manager进行自定义节点管理时&#xff0c;许多用户会遇到节点列…

作者头像 李华
网站建设 2026/7/7 19:03:43

TaskFlow任务编排框架:5分钟学会Java业务流程可视化编排

TaskFlow任务编排框架&#xff1a;5分钟学会Java业务流程可视化编排 【免费下载链接】taskflow taskflow是一款轻量、简单易用、可灵活扩展的通用任务编排框架&#xff0c;基于有向无环图(DAG)的方式实现&#xff0c;框架提供了组件复用、同步/异步编排、条件判断、分支选择等能…

作者头像 李华
网站建设 2026/7/7 13:49:46

RBD 常用命令速查表

好&#xff0c;那我直接把 A 同学要交付的《RBD 常用命令速查表》完整写出来。 这份文档我按**“实验课 / 技术文档”标准来写**&#xff0c;做到&#xff1a; ✅ 可直接交作业✅ 适合新手快速查✅ 也经得起老师/助教检查✅ 后续方便 B 同学按表实操交叉测试 你可以原样使用&am…

作者头像 李华