介绍
C++
多线程是指在C++
程序中使用多个线程来实现并发执行的功能。多线程可以提高程序的性能和响应速度,同时也可以简化程序的设计和实现。
在C++
中,可以使用标准库中的thread
类来创建和管理线程。thread
类提供了多个构造函数和成员函数,可以用于创建新线程、等待线程结束、获取线程ID
等操作
using namespace std::chrono; using namespace std;
using ull = unsigned long long; ull OddSum = 0; ull EvenSum = 0;
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; }
int main() {
ull start = 0, end = 1900000000;
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 << "OddSum : " << OddSum << endl; cout << "EvenSum: " << EvenSum << endl; cout << "Sec: " << duration.count() / 1000000 << endl; return 0; }
|
创建线程的五种类型
-
function_pointer
// 1.函数指针
using namespace std;
void fun(int x) { while (x-- > 0) { cout << x << endl; } } // 注意:如果我们创建多线程 并不会保证哪一个先开始 int main() { std::thread t1(fun, 10); // std::thread t2(fun, 10); t1.join(); // t2.join(); return 0; }
|
C++ 中,函数名可以被视为指向函数代码的指针。在这里,fun
函数被用作线程的入口函数,它会在新的线程中被执行。在创建线程时,我们将 fun
函数的地址作为参数传递给了 std::thread
构造函数。
-
lambda_function
// 1.函数指针 #include <thread> #include <iostream>
using namespace std;
// 注意:如果我们创建多线程 并不会保证哪一个先开始 int main() { // 2.Lambda函数 auto fun = [](int x) { while (x-- > 0) { cout << x << endl; } }; // std::1.thread t1(fun, 10); // 也可以写成下面: std::thread t1_1([](int x) { while (x-- > 0) { cout << x << endl; } }, 11); // std::1.thread t2(fun, 10); // t1.join(); t1_1.join(); // t2.join(); return 0; }
|
-
functor
using namespace std;
// 3.functor (Funciton Object) class Base { public: void operator()(int x) { while (x-- > 0) { cout << x << endl; } } };
int main() { thread t(Base(), 10); t.join(); return 0; }
|
-
no_static_member_function
using namespace std;
// 4.Non-static member function class Base { public: void fun(int x) { while (x-- > 0) { cout << x << endl; } } };
int main() { Base b; thread t(&Base::fun,&b, 10); t.join(); return 0; }
|
函数名与函数指针的相关解释
第一种:函数名与FunP
函数指针都是函数指针。fun
是一个函数指针常量,funP
是一个函数数指针变量。
虽然通过常量与变量来解释函数名无法赋值可以帮助理解,但是我们发现对fun
赋值时编译器给的错误提示并不是说对常量进行赋值,而是告诉我们=
号两端格式不匹配。对此,第二种理解更合理。
第二种:函数名和数组名实际上都不是指针,但是,在使用时可以退化成指针,即编译器可以帮助我们实现自动的转换。
这也可以解释为什么当我们在=
号右侧使用函数名时,无论是取值还是取地址都没有问题,因为编译替我们做了相当于强制类型转换的工作,而在当函数名在=
号左侧时,右侧的函数指针并没有这个功能,毕竟他们俩不是同一种结构。
-
static_member_function
非静态成员函数只能通过类的对象进行调用,因为它们需要访问对象的状态。这与静态成员函数不同,后者可以直接通过类名进行调用
using namespace std;
// 4.static member function class Base { public: static void fun(int x) { while (x-- > 0) { cout << x << endl; } } };
int main() { thread t(&Base::fun, 10); t.join(); return 0; }
|
Join 与 Detachs
-
join
using namespace std;
void run(int count) { while (count-- > 0) { cout << count << endl; } std::this_thread::sleep_for(chrono::seconds(3)); }
int main() { thread t1(run, 10); cout << "main()" << endl; t1.join(); if (t1.joinable()) { t1.join(); } cout << "main() after" << endl; return 0; }
|
-
detach
using namespace std;
void run(int count) { while (count-- > 0) { cout << count << endl; } std::this_thread::sleep_for(chrono::seconds(3)); }
int main() { thread t1(run, 10); cout << "main()" << endl; t1.detach(); if(t1.joinable()) t1.detach(); cout << "main() after" << endl; return 0; }
|
mutex in C++ Threading
-
这段代码创建了两个线程t1
和t2
,它们都会执行countgold()
函数,用于计算一个共享变量sum
的值。countgold()
函数使用了一个互斥锁来保护共享变量sum
的访问。
-
main()
函数启动了两个线程,并等待它们完成。一旦两个线程都完成了计算,程序就会输出sum的最终值。由于使用了互斥锁,程序可以保证每次只有一个线程能够修改sum变量,因此最终结果是可预测的。
using namespace std;
int sum = 0; //shared
mutex m;
void *countgold() { int i; //local to each thread for (i = 0; i < 10000000; i++) { m.lock(); sum += 1; m.unlock(); } return NULL; }
int main() { thread t1(countgold); thread t2(countgold);
//Wait for both threads to finish t1.join(); t2.join();
cout << "sum = " << sum << endl; return 0; }
|
mutex
提供了两个主要的操作:lock()
和unlock()
。在访问共享资源之前,线程需要调用lock()
函数来获取互斥锁;在访问完成之后,线程需要调用unlock()
函数来释放互斥锁。当一个线程已经获取了互斥锁时,其他线程将无法获取该锁,直到该线程释放了锁。这样可以保证在任何时候只有一个线程能够访问共享资源,从而避免了竞态条件的发生。
Reference
[1] C++ 那些事: https://github.com/Light-City/CPlusPlusThings