这是我参与2022首次更文挑战的第14天,活动详情查看:2022首次更文挑战
线程是一个让人又爱又恨的,对于普通程序员,前端也好后端也好,很少有机会会接触到线程这个东西。线程出现主要是性能或者并发。这些都是框架设计人员应该考虑的。不多在面试中可能会被问到,
线程和进程
什么是线程,这个 CPU 调度最小单元。一个进程可以有多个线程,线程开销要小于进程,不过线程容器发生共享资源。在 window 系统来说,进程开销比较大,所以在 window 中是鼓励大家在进程下进行多线程编程。而在 linux 系统下,创建一个进程和创建一个线程的开销差不多,
分享来回的一个问题,就是如何理解线程,今天侧重实践,关于线程原理和概念就点到为止。
int main()
{
return 0;
}
每一个我们写应用都是运行在一个线程上,默认线程就是 main() ,线程可以看成轻量级的进程,比较理想方式就是将进程分为多个平行执行的线程。
#include <iostream>
#include <thread>
#include <chrono>
#include <algorithm>
using namespace std;
using namespace std::chrono;
typedef unsigned long long ull;
ull OddSum = 0;
ull EvenSum = 0;
我们可以用 typedef 给 unsigned long long 类型定义一个别名ull。
然后来创建两个函数分别是 findEven 和 findOdd ,分别是在数列中对所有偶数进行求和对所有奇数进行求和
void findEven(ull start, ull end)
{
for (ull i = start; i <= end; i++)
{
if ((i & 1) == 0) {
EvenSum += i;
}
}
}
void findOdd(ull start, ull end)
{
for (ull i = start; i <= end; i++)
{
if ((i & 1) == 1) {
OddSum += i;
}
}
}
我们创建一个比较大序列 ull start = 0, end = 1900000000 然后分别调用findOdd和findEven 来分别对其中奇数和偶数进行求和
int main()
{
ull start = 0, end = 1900000000;
findOdd(start, end);
findEven(start, end);
cout << "OddSum : " << OddSum << endl;
cout << "EvenSum : " << EvenSum << endl;
return 0;
}
接下来我们引入 high_resolution_clock 来计算执行函数所消耗的时间,以便于我们对比引入线程前后之间差别
auto startTime = high_resolution_clock::now();
findOdd(start, end);
findEven(start, end);
auto stopTime = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(stopTime - startTime);
cout << duration.count() / 1000000 << endl;
8
OddSum : 902500000000000000
EvenSum : 902500000950000000
早在 c++ 11 版本之前,在语言层面是不支持线程的,需要调用系统 API 来实现线程,这样一来就给开发者带来许多不便。
我们对上面程序进行优化,所谓的优化就是将线程引入,我们第一个 work 类型为 thread,然后我们将函数作为第一个参数传入到 work_find_odd 如果传入线程的函数没有参数,只要这样做就可以了,如果函数有参数,我们就将参数从第二个参数起依次传入到线程,因为第一个参数是函数,为了让主线程main 等待这两个线程执行完后在继续执行,我们可以调用线程的 join 方法。接下来会演示几种常见创建线程的方法。
int main()
{
ull start = 0, end = 1900000000;
auto startTime = high_resolution_clock::now();
std::thread work_find_odd(findOdd, start, end);
std::thread work_find_even(findEven, start, end);
//findOdd(start, end);
//findEven(start, end);
work_find_even.join();
work_find_odd.join();
auto stopTime = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(stopTime - startTime);
cout << duration.count() / 1000000 << endl;
cout << "OddSum : " << OddSum << endl;
cout << "EvenSum : " << EvenSum << endl;
return 0;
}
创建线程方式
指针函数
void fun(int x) {
while (x-- > 0)
{
cout << x << endl;
}
}
int main()
{
std::thread work_one(fun, 11);
work_one.join();
return 0;
}
Lambda 函数
int main()
{
auto fun = [](int x) {
while (x-- > 0)
{
cout << x << endl;
}
};
std::thread work_one(fun, 11);
work_one.join();
return 0;
}
类
class Base {
public:
void operator ()(int x) {
while (x-- > 0) {
cout << x << endl;
}
}
};
std::thread work_one(Base(), 11);
类的方法
将类的方法传入到线程
class Base
{
public:
void run(int x) {
while (x-- > 0)
{
cout << x << endl;
}
}
};
std::thread work_one(&Base::run,&b, 11);
类的静态方法
这一次因为是类的静态方法所以不需要传实例&Base::run 然后传入方法run 的参数
class Base
{
public:
static void run(int x) {
while (x-- > 0)
{
cout << x << endl;
}
}
};
std::thread work_one(&Base::run, 11);