线程

计算机执行程序,必须一行一行执行代码。
一个程序跑起来,默认有主线程,它从 main 函数开始跑:新创建一个线程,它也必须从某一段代码开始跑。这段代码,必须是一个函数。所以 C++ 规定:创建线程时,必须给它一个函数作为入口,线程启动后,必须去执行一个函数,线程要执行代码 → 代码必须写在函数里 → 所以线程必须绑定函数
std::thread 的构造函数是:thread(函数名); 意思就是:创建一个线程,让它去执行此函数。

//C++11 开始,几乎所有标准容器都有 emplace 系列函数,核心就三件:直接在容器内存里构造对象、不产生临时、不拷贝。
//一、顺序容器通用(vector /deque/list 都有)
//1. emplace_back (参数...)
//对应:push_back
//作用:在末尾原地构造
//2. emplace_front (参数...)
//对应:push_front
//作用:在头部原地构造
//容器:deque、list、forward_list
//3. emplace (迭代器位置,参数...)
//对应:insert
//作用:在指定位置前原地构造
//二、forward_list 独有
//emplace_after (迭代器,参数...)
//对应:insert_after
//作用:在迭代器后面构造
//三、关联容器(map /set/unordered_map…)
//1. emplace (参数...)
//作用:直接构造 key-value(或元素)并插入
//2. emplace_hint (迭代器提示,参数...)
//作用:给位置提示,帮助更快插入
//四、容器适配器(stack /queue/priority_queue)
//emplace (参数...)
//对应:push
//作用:在底层容器原地构造

threads.emplace_back(increment);
//等价于
thread t(increment);  // 创建线程,让它跑 increment 函数
threads.push_back(t);

vector::emplace_back会直接在 vector 内部调用 thread 的构造函数,相当于:new (&space) thread(increment);

new (&space) thread(increment);//定位 new /placement new;在一块已经准备好的内存里,直接创建一个线程对象!
//它不申请新内存,只在指定位置构造对象。
//普通 new(我们平时用的)
thread* t = new thread(increment);//向操作系统申请一块新内存;在这块内存里 创建线程
new (&space) thread(increment);//定位 new;不申请内存!直接在 &space 这块已经有的内存上,创建线程对象
//在 space 这块内存上,直接构造一个线程,让它跑 increment 函数
threads.emplace_back(increment);//vector 内部做的事:给新元素腾出位置(连续内存);在这个位置上直接创建线程;不拷贝、不移动、不浪费,内部用的就是:new (&空闲位置) thread(increment);

所以:
emplace_back(increment) = 创建线程 + 绑定函数

std::thread 禁止复制。原因:线程是操作系统里的真实执行流,是唯一的、不能克隆的, C++ 规定:thread 没有拷贝构造函数,不能复制。所以遍历线程必须用 &(引用),for (auto& t : threads) ,相当于直接用原来的线程,不创建新的,不拷贝

t.join () 是 “等待线程结束” ;
join 的官方定义:
*Blocks the current thread until the thread identified by this finishes execution.暂停当前线程,直到这个子线程跑完,才继续往下走。如果不等待:主线程直接结束,程序直接退出,子线程还没跑完就被杀死,结果错误、崩溃;join 使得主线程 卡住不动,一直等子线程运行到 } 结束,子线程结束后,join 才放行,主线程继续

lock_guard<mutex> lock(mtx);//lock_guard锁的管理员,自动加锁、自动解锁,创建时 → 自动 lock (),离开 {} 时 → 自动 unlock ()
//<mutex>管理的是 mutex 这把锁
//lock管理员名字
//(mtx)把全局的那把锁 mtx 交给管理员

lock_guard 是一个类模板,lock 是创建出来的对象,(mtx) 是给构造函数传参(把锁传进去),当离开大括号 {},C++ 自动调用析构函数 ~lock_guard():是 C++ 的 RAII 机制(资源获取即初始化)

std::atomic 是 C++11 引入的原子操作模板,用于多线程编程中无需加锁就能安全地访问共享变量。atomic = 自动保证操作的"不可分割性",多线程访问时不会出现数据竞争
只有简单的类型:int, bool, char, long, 指针,可以用atomic,string、vector 不行
tomic 比锁快,因为锁是操作系统管的,atomic 是 CPU 硬件管的

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐