C++多线程编程(1):线程的创建方式

文章首发于我的个人博客:欢迎大佬们来逛逛

文章目录

  • 进行与线程
  • C++中如何实现多线程
  • 创建线程的多种方式
    • 无参函数
    • lambda表达式
    • 常成员函数
    • not常成员引用函数
    • 智能指针
    • 仿函数
    • 类的普通成员函数
    • 综合测试

进行与线程

多线程是指多个线程并发执行的过程。

进程与线程的关系:

  • 进程是一个独立运行的应用程序
  • 线程是指进程内独立执行的一个单元,一个进程中可能有多个线程。

C++中如何实现多线程

使用 #include <thread> 头文件,里面定义了很多的线程函数。

其中,使用 thread 创建一个线程.

比如我有两个函数,分别是:

  • print1是主线程。
  • 下面四个函数分别是子线程。
void print1() {std::cout << "主线程\n";
}
void printtttt1() {Sleep(2000);std::cout << "子线程1\n";
}
void printtttt2() {Sleep(2000);std::cout << "子线程2\n";
}
void printtttt3() {Sleep(2000);std::cout << "子线程3\n";
}

现在我们想让他们四个同时执行?如何操作。

  1. 首先来创建线程对象:

thread 用作线程对象类型,然后传递一个函数指针(以模板形式)给到这个对象,则这个对象就是一个线程对象

我们将这三个子线程分别为三个不同的线程对象。print1为主线程。

std::thread t1(printtttt1);
std::thread t2(printtttt2);
std::thread t3(printtttt3);

创建完成后我们使用 join将子线程添加到主线程中:

t1.join(); 
t2.join();
t3.join();

然后运行,就会发现,三个子线程和主线程同时结束,说明多线程有效。

int main() {std::thread t1(printtttt1);std::thread t2(printtttt2);std::thread t3(printtttt3);//t.join(); //子线程加入主线程//detach: 子线程和主线程各自玩个的,等待主线程执行完毕t1.join(); t2.join();t3.join();print1();return 0;
}

观察到细节:

  • 三个子线程都有一个等待两秒的功能,如果不是多线程,则很容易想到单纯的运行这四个函数可能需要6秒多才完成
  • 但是他们四个是同时完成的,即只用了两秒
  • 并且我们没有限制线程之间的执行顺序,因此他们的顺序是任意的。

在这里插入图片描述


join函数就是将子线程加入到主线程,然后和主线程一起执行完毕。

还有个 detach函数:

  • detach: 子线程和主线程各玩各的的,等待主线程执行完毕则停止。
t1.detach();
t2.detach();
t3.detach();
print1();

则会出现什么?

  • 程序立刻结束,我管你子线程执行了没有,只要我的主线程结束了,则程序就结束。 因此程序直接执行主线程函数,而不会执行三个子线程。

在这里插入图片描述


joinable:对线程是否可以join和detach操作进行判断。即一个线程只能进行一次join或者detach操作,如果你写了很多的代码,明明已经join过一次了,但是忘记了,因此又join了一次,这时就会 报错!!!

该函数在可以 join 或 detach 的时候返回true,否则返回false。

因此常见的可以避免错误的方式:

if (t1.joinable()) {t1.join(); //t1.detach()}

创建线程的多种方式

thread类型的构造函数是怎样的呢? 它可以构造什么样的线程函数对象呢?

template <class _Fn, class... _Args,   .......... >
explicit thread(_Fn&& _Fx, _Args&&... _Ax) {_Start(_STD forward<_Fn>(_Fx), _STD forward<_Args>(_Ax)...);
}
  • Fn:接受一个函数指针。
  • Args:接受函数的参数。

无参函数

这是最简单的创建线程的方式:

// 1. 传递无参void函数
void print() {std::cout << "子线程: " << "传递无参void函数\n";
}
void create1() {std::thread t1(print);t1.join(); //加入主线程
}

lambda表达式

// 2. 传递lambda表达式
void create2() {std::thread t1([]() {std::cout << "lambda表达式\n";});if (t1.joinable()) {t1.join();}
}

常成员函数

  • 普通内置类型:int
  • 常引用:const string& ; const int&
  • 常指针:const int*
  • 都可以直接传递
// 3. 传递有参函数
// 3.1  普通参数
void print2(int num, const std::string& name, const int age, const int& yina, const int* cp) {std::cout << "num: " << num << " name: " << name << " age: " << age << " yina: "<< yina << " cp: " << *cp << '\n';
}
void create3() {int num = 10, age = 20, yina = 999, cpnum = 50;std::thread t1(print2, num, "你好", age, yina, &cpnum);if (t1.joinable()) {t1.join();}
}

not常成员引用函数

  • not常引用: 如果是**不带const**的引用类型,则必须使用 std::ref 修饰,否则会报错:
  • not常指针:不会报错。
// 必须加以 ref 修饰;否则就传递const的引用
void print3(int& num) {std::cout << "引用 num: " << num << '\n';
}
void create4() {int num = 10;std::thread t1(print3, std::ref(num));if (t1.joinable()) {t1.join();}
}//不会报错,const和非const的指针都不会报错,传递地址即可
void print4(int* num) {std::cout << "指针 num: " << *num << '\n';
}
void create5() {int num = 10;std::thread t1(print4, &num);if (t1.joinable()) {t1.join();}
}

智能指针

传递智能指针 unique_ptr 需要加 move移动,因为unique_ptr只允许存在一份,但是移动后本地将消失。

void print5(std::unique_ptr<int> ptr) {std::cout << "智能指针: " << *ptr.get() << '\n';
}
void create6() {std::unique_ptr<int> pointer(new int{ 100 });std::thread t1(print5, std::move(pointer));if (t1.joinable()) {t1.join();}//nullstd::cout << "移动之后,智能指针: " << pointer.get() << '\n';
}

仿函数

直接传递即可。

class Foo {
public:Foo() {}void operator()() {std::cout << "仿函数\n";}
};
void create7() {Foo f = Foo();//1. 仿函数对象std::thread t1(f);if (t1.joinable()) {t1.join();}//2. 匿名函数对象std::thread t2((Foo()));if (t2.joinable()) {t2.join();}
}

类的普通成员函数

函数指针的形式,先传递类名所对应的**函数地址,然后再传递类对象**。

class Aoo {
public:Aoo() {}void test() {std::cout << "普通成员函数\n";}
};
void create8() {Aoo a = Aoo();std::thread t1(&Aoo::test,a);if (t1.joinable()) {t1.join();}
}

综合测试

int main() {create1();create2();create3();create4();create5();create6();create7();create8();return 0;
}

在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/194130.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QTableWidget——表格的合并与拆分

一、整体思路 表格的操作使用QTableView::setSpan可以实现表格的行和列的合并 表格拆分没有对应的处理函数 主要思路&#xff1a;对表格的属性、内容、拆分与合并的参数进行存储&#xff0c;在进行拆分时对表格内容进行重新创建&#xff08;不考虑效率问题&#xff09; 二、效…

C/C++ 语言 ‘ == ‘ 运算符仅适用于算数表达式

示例代码&#xff1a; #include <stdio.h>typedef struct {int a;int b; } TestStruct;int main(void) {TestStruct testA { 0 }, testB { 0 };if (testA testB) {printf("You can do this!\n");}return 0; }

HTTP1.0协议详解

前言主要特点存在的不足与HTTP1.1的区别在Java中应用HTTP1.0协议知识拓展 前言 HTTP是由蒂姆伯纳斯李&#xff08;Tim Berners-Lee&#xff09;爵士创造的。他在1989年提出了一个构想&#xff0c;借助多文档之间相互关联形成的超文本&#xff08;HyperText&#xff09;&#x…

【心得】PHP的文件上传个人笔记

目录 1 php的文件上传绕过 黑名单绕过 2 php文件上传的00截断 3 iconv字符转换异常后造成了字符截断 4 文件后缀是白名单的时候的绕过 web服务器的解析漏洞绕过 5.高级文件上传绕过 1 .htaccess nginx.htaccess 2 服务端内容检测 3 配合伪协议来绕过 4.配合日志包含绕…

智能电力监测系统

智能电力监测系统是一种先进的电力监控技术&#xff0c;它结合了互联网、物联网、大数据、人工智能等先进技术&#xff0c;对电力系统的运行状态进行实时监测和分析。以下是智能电力监测系统的主要功能和优势&#xff1a; 一、主要功能&#xff1a; 实时数据监测&#xff1a;智…

时间序列与 statsmodels:预测所需的基本概念(2)

时间序列与 statsmodels&#xff1a;预测所需的基本概念&#xff08;2&#xff09; 维托米尔约万诺维奇 跟随 出版于 走向发展 4 分钟阅读 2022 年 1 月 31 日 8 一、说明 在使时间序列平稳后&#xff0c;在本博客中我们应用 SARIMAX 预测并进行深入解释。 二、关于平稳性 …

接口自动化测试中解决接口间数据依赖

在实际的测试工作中&#xff0c;在做接口自动化测试时往往会遇到接口间数据依赖问题&#xff0c;即API_03的请求参数来源于API_02的响应数据&#xff0c;API_02的请求参数又来源于API_01的响应数据。 因此通过自动化方式测试API_03接口时&#xff0c;需要预先请求API_02接口&a…

轻松掌控财务,分析账户花销,明细记录支出情况

随着科技的发展&#xff0c;我们的生活变得越来越智能化。然而&#xff0c;对于许多忙碌的现代人来说&#xff0c;管理财务可能是一件令人头疼的事情。复杂的账单、花销、收入&#xff0c;这些可能会让你感到无从下手。但现在&#xff0c;我们有一个全新的解决方案——一款全新…

[qemu逃逸] XNUCA2019-vexx

前言 这题没有去符合, 题目本身不算难. 用户名: root 密码: goodluck 设备逆向 题目没有去符合, 所以其实没啥好讲了, 就列一些笔者认为关键的地方 这里的定义了两块 mmio 内存区. 然后看下设备实例结构体: 可以看到 QEMUTimer, 所以多半就是劫持 dma_timer 了. 漏洞点在…

传输层协议-TCP协议

目录 TCP协议格式理解可靠性序号与确认序号16位窗口大小六个标志位连接管理机制三次握手四次挥手 确认应答机制&#xff08;ACK&#xff09;超时空重传机制流量控制滑动窗口拥塞控制延迟应答捎带应答面向字节流粘包问题TCP异常情况TCP小结基于TCP应用层协议TCP/UDP对比用UDP实现…

【STL】:反向迭代器

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下有关反向迭代器的模拟实现&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通…

吐血整理,金融银行测试的“火“到底在哪里?银行测试真正实施...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 银行里的软件测试…