wait-notify之间做了什么
释放锁并进入等待原子性阶段当你调用cv.wait(lock)时底层会立即执行以下操作释放锁自动释放当前线程持有的std::unique_lockstd::mutex。加入队列将当前线程放入该条件变量的等待队列中。进入休眠挂起当前线程不再消耗 CPU 资源。核心细节释放锁和进入等待这两个动作是原子性的。这意味着不会出现“刚释放锁还没进入等待队列通知就来了”的情况即错失信号。被唤醒并尝试重新获取锁当另一个线程调用cv.notify_one()或cv.notify_all()时唤醒操作系统将线程从等待队列中移出状态变为“就绪”。重新抢锁线程在wait内部尝试重新获取acquire之前释放的那个mutex。阻塞等待锁如果锁此时被其他线程持有比如通知者还没释放锁被唤醒的线程会停在wait内部直到它抢到了锁。返回阶段只有当成功重新持有锁后cv.wait(lock)才会结束阻塞并返回。此时你的线程恢复了对共享资源的独占访问权限。信号丢失虚假唤醒信号丢失A发送信号唤醒BA已经发送信号但是B还没进入等待就会倒是B收不到A的信号这个信号就丢失了。虚假唤醒感官上是程序中没有调用notify唤醒某些处于阻塞的线程。如何解决在调用wait前检查条件生产者只有在队列满的情况下阻塞消费者在队列空的情况下阻塞使用if检查条件可以避免信号丢失。使用while检查变量可以解决信号丢失和虚假唤醒。为什么if可以防止信号丢失信号丢失Lost Wake-up发生在生产者发出了“队列已满”的信号但消费者此时并没有在等待或者生产者在消费者还没来得及进入wait状态时就发送notify。检查条件的必要性在调用wait()之前检查条件无论是if还是while本质上是为了确认当前是否真的需要阻塞。逻辑消费者进入临界区后先看一眼队列。如果队列不为空它直接拿走数据根本不调用wait()。这样即使生产者之前发过信号消费者也已经处理了数据不会因为错过信号而死锁。为什么while是金标准使用while循环检查条件被称为Mesa-style monitoring。它的逻辑是被唤醒后必须再次检查条件。使用while检查状态等效于 cv.wait(unique_lock(mutex),pred)// 伪代码cv.wait(lock, pred) 的等效实现 while (!pred()) { wait(lock); }线程局部存储thread_local 每一个线程都是独立的副本变量线程销毁时临时变量销毁。truct ThreadContext { int thread_id; std::string name; std::vectorint local_data; ThreadContext() : thread_id(0) { std::cout 构造线程局部结构体 std::endl; } ~ThreadContext() { std::cout 析构线程局部结构体线程ID: thread_id std::endl; } }; // C11 thread_local thread_local ThreadContext ctx;如何调试gdb命令## 编译生成 加-g g -g test.cpp test -pthread ## 帮助 help /h ## 启动调试 gdb test ## 查看代码 list ## 运行 run /r 运行到第一个断点 start 运行到第一行执行程序 ## 打断点 break / b 行号/函数名 ## 查看所有断点 info b info breakpoints ## 执行 next / n 下一步 不进函数 逐过程 step / s 下一步 进函数 逐语句 continute /c 跳转下一个断点 finish 结束当前函数 info 查看函数局部变量的值 ## 退出 quit /q ## 输出 print / p 变量 p m_vector p m_map p *(m_vector._M_impl._start_)m_vector.size() display 追踪具体变量值 undisplay 取消追踪 watch 设置观察点 变量修改时打印显示 # x 查看内存 ## 查看所有进程 info thread ## 跳转进程 thread i ## 打印调用独占 bt ## 打印所有线程的调用堆栈 thread apply all bt ## 生成日志文件开启日志模式 set logging on # 日志功能开启 ## 观察点 watchpoint watch set scheduler-locking on #锁定调度。设置后当你 next 时只有当前线程运行其他线程暂停。防止你在