C++11:多线程
传统的C++(C++11之前)中并没有引入线程这个概念
C++11引入了头文件<thread>,提供了 管理线程 保护共享数据 线程间同步操作 原子操作等
线程(thread)是操作系统能够进行运算调度的最小单位,它被包含在进程中,是进程中的实际运作单位,一条线程指的是进程中一个单一顺序的控制流,一个进程可以并发多个线程,每个线程执行不同的任务
linux中使用 <pthread.h>
创建线程
#include <thread>
std::thread
任务函数可以是普通函数 类的静态函数 类的非静态函数 匿名函数 仿函数
#include <thread> #include <windows.h> #include <iostream> void func(int num, const std::string& str) { for (int i = 0; i < 10; i++) { std::cout << "func" << num << str << std::endl; Sleep(1000); } } int main() { //报错 内部执行顺序混乱 std::thread t1(func, 3, "continue"); std::cout << "start" << std::endl; for (int i = 0; i < 10; i++) { std::cout << "main continue" << std::endl; Sleep(1000); } std::cout << "end" << std::endl;
//t1.join(); return 0; }
#include <thread> #include <windows.h> #include <iostream> void func(int num, const std::string& str) { for (int i = 0; i < 10; i++) { std::cout << "func" << num << str << std::endl; Sleep(1000); } } //仿函数 class MyThread1 { public: void operator() (int num, const std::string& str) { for (int i = 0; i < 10; i++) { std::cout << "仿函数" << num << str << std::endl; Sleep(1000); } } }; class MyThread2 { public: //类的静态成员函数 static void s_fun(int num, const std::string& str) { for (int i = 0; i < 10; i++) { std::cout << "static members function" << num << str << std::endl; Sleep(1000); } } }; class MyThread3 { public: //类的普通成员函数 void fuc(int num, const std::string& str) { for (int i = 0; i < 10; i++) { std::cout << "class func" << num << str << std::endl; Sleep(1000); } } }; int main() { //普通函数创建线程 std::thread t1(func, 1, "continue1"); //lambda函数创建线程 auto f = [](int num, const std::string& str) { for (int i = 0; i < 10; i++) { std::cout << "lambda" << num << str << std::endl; Sleep(1000); } }; std::thread t2(f, 0, "continue2"); //仿函数创建线程 std::thread t3(MyThread1(), -1, "continue3"); //静态成员函数创建线程 std::thread t4(MyThread2::s_fun, -2, "continue4"); //类的普通成员函数创建线程 MyThread3 mtf; std::thread t5(&MyThread3::fuc, &mtf, -3, "continue5"); std::cout << "start" << std::endl; for (int i = 0; i < 10; i++) { std::cout << "main continue" << std::endl; Sleep(1000); } std::cout << "end" << std::endl; t1.join(); t2.join(); t3.join(); t4.join(); t5.join(); return 0; }
// CppTest.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include <atomic> #include <iostream> #include <thread> #include <chrono> #include <thread> using namespace std; int i = 0; const int maxCnt = 1000000; void mythread() { for (int j = 0; j < maxCnt; j++) { i++; //线程同时操作变量 } } int main() { auto begin = chrono::high_resolution_clock::now(); thread t1(mythread); thread t2(mythread); t1.join(); t2.join(); auto end = chrono::high_resolution_clock::now(); cout << "i =" << i << endl; cout << "time :" << chrono::duration_cast <chrono::microseconds>(end - begin).count() * 1e-6 << "s" << endl; }
线程资源回收
同一个进程的多个线程共享进程的栈空间,但每个子线程都拥有自己的栈空间
在主程序中调用 join() 成员函数等待子线程退出,回收资源。如果子线程已退出,join() 函数会立即返回,否则会发生阻塞,直到子线程退出
在子程序中调用 detach()成员函数分离子线程,子线程退出时,系统自动回收资源。子程序被分离后,不能 join(),否则程序会报错。在分离之后主线程不能退出,退出后直接结束。
线程成员函数
get_id() 返回线程ID
线程安全
在拥有共享数据的多条线程并行执行程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的运行,不会出现数据污染等意外情况
同一个进程中多个线程共享该进程的全部系统资源,多线程访问同一个资源时会产生冲突
顺序性
CPU的执行顺序和代码运行的先后顺序
可见性
多个线程可见共享变量的修改
原子性
保证线程安全
volatile 关键字
原子操作(原子类型)
线程同步(锁)
线程同步
多个线程协同工作,需要共享资源
互斥锁(互斥量)
条件变量
生产/消费者模型
互斥锁
加锁和解锁确保同一时间只有一个线程访问共享资源
访问共享资源之前加锁,访问完成后释放锁
如果某线程保持有锁,其他线程形成等待队列
C++11提供了四种互斥锁:
mutex:互斥锁
timed_mutex:带超时机制的互斥锁
recursive_mutex:递归互斥锁
recursive_timed_mutex:带超时机制的递归互斥锁
#include <mutex>
#include <iostream> #include <thread> #include <atomic> #include <mutex> int g_a = 0; //定义为原子类型 std::mutex mtx; //创建互斥锁对象,保护共享资源g_a变量
//注意两个互斥量的时候,会发生死锁 void func() { for (int i = 0; i < 10000000; i++) { mtx.lock(); g_a++; mtx.unlock(); } } int main() { std::thread t1(func); std::thread t2(func); t1.join(); t2.join(); std::cout << g_a << std::endl; return 0; }
// CppTest.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include <atomic> #include <iostream> #include <thread> #include <chrono> #include <thread> #include <mutex> using namespace std; std::mutex var_mutex; int i = 0; const int maxCnt = 1000000; void mythread() { for (int j = 0; j < maxCnt; j++) { lock_guard<mutex> guard(var_mutex); i++; //线程同时操作变量 } } int main() { auto begin = chrono::high_resolution_clock::now(); thread t1(mythread); thread t2(mythread); t1.join(); t2.join(); auto end = chrono::high_resolution_clock::now(); cout << "i =" << i << endl; cout << "time :" << chrono::duration_cast <chrono::microseconds>(end - begin).count() * 1e-6 << "s" << endl; }
线程原子
C++11 提供了atomic<T> 模板类(结构体),用于支持原子类型,模板参数可以是bool char int long longlong 指针类型(不支持浮点类型和自定义类型)
原子操作由CPU指令提供支持,它的性能比锁和消息传递更高,并且不需要处理加锁和解锁的问题,支持修改、读取、交换、比较并交换等操作
#include<atomic>
运算速度要比互斥锁要快,相当于轻量化的锁
#include <iostream> #include <thread> #include <atomic> #include <mutex> std::atomic<int> g_a = 0; //定义为原子类型 void func() { for (int i = 0; i < 10000000; i++) { g_a++; } } int main() { std::thread t1(func); std::thread t2(func); t1.join(); t2.join(); std::cout << g_a << std::endl; return 0; }
<thread>
join() detach() get_id() yield() sleep_for() sleep_until()
#include <thread>
int main()
{
std::thread t1;
std::cout << t1.get_id() << std::endl;
return 0;}
//线程函数为函数指针
std::thread t1(ThreadFunc, 10);//线程函数为lambda表达式
std::thread t2([] {std::cout << "Thread2" << std::endl; });//线程函数为函数对象
TF tf;
thread t3(tf);t1.join();
t2.join();
t3.join();
std::cout << "Main thread" << std::endl;
return 0;
#include <iostream>
#include <thread>
#include <mutex>int main()
{int n = 100;
std::mutex mtx;std::thread t1([&]() {
int i = 1;
for (; i < n; i +=2)
{
std::unique_lock<std::mutex> lock(mtx);
std::cout << i << std::endl;
}});
std::thread t2([&]() {
int j = 2;
for (; j < n; j += 2)
{
std::unique_lock<std::mutex> lock(mtx);
std::cout << j << std::endl;
}
});t1.join();
t2.join();
return 0;
}
<mutex>
<atomic>
<condition_variable>
<future>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)