C++中unique_lock.lock()触发中止错误及互斥保护疑问
C++ std::unique_lock 与条件变量疑问解答
问题1:std::unique_lockstd::mutex构造时是否会锁定互斥量?为何示例中所有线程都能通过该行,它是否实现互斥保护?
- 用
std::unique_lock<std::mutex> lck(mtx);这种无额外参数的构造方式时,会自动锁定传入的互斥量,同一时间只有一个线程能成功构造并持有锁,其他线程会阻塞在构造行等待锁释放。 - 你看到所有线程都能走到构造行之后的代码,核心原因是
cv.wait(lck);的特殊行为:当线程进入wait等待条件变量时,会自动释放持有的锁。第一个线程拿到锁,输出后进入wait,锁被释放;第二个线程立刻拿到锁,输出后进入wait,锁再次释放……以此类推,最终所有线程都会卡在wait的循环里,看起来就像"都通过了构造行"。unique_lock的构造本身是严格互斥的,不存在多个线程同时持有锁的情况。
问题2:为何调用lck.lock()会触发中止错误?注释该行后线程会连续启动,我原以为构造后其他线程无法进入该区域。
- 中止错误的根源是重复加锁:
unique_lock构造时已经自动锁定了mtx,此时再调用lck.lock()就是对同一个互斥量再次加锁,这属于未定义行为,绝大多数C++标准库实现会直接触发程序中止来提示错误。 - 注释掉
lck.lock()后,线程连续输出"thread Starts"的原因还是和cv.wait有关:每个线程拿到锁后,输出完就进入wait,wait会释放锁,让下一个线程能立刻获取锁并执行输出步骤。你之前误以为构造后其他线程无法进入,是没注意到wait会临时释放锁——unique_lock持有锁的时间不是从构造到析构的全程,wait会主动释放锁,让其他线程有机会进入临界区。
你的测试代码(已修正标准语法问题)
#include <mutex> #include <thread> #include <chrono> #include <iostream> using namespace std; condition_variable cv; bool ready = false; mutex mtx; void print_id(int id) { // why all the threads can pass this line? std::unique_lock<std::mutex> lck(mtx); //i knew about the concept of two times locking, just thought there //is something wrong with the constructor or i dont understand lck.lock(); // Having this line gives me abort. std::cout << "thread Starts: " << id << '\n'; while (!ready) cv.wait(lck); // ... std::cout << "thread Ends: " << id << '\n'; } void go() { std::unique_lock<std::mutex> lck(mtx); ready = true; cv.notify_all(); } int main() { std::thread threads[5]; // spawn 5 threads: for (int i = 0; i < 5; ++i) { this_thread::sleep_for(chrono::milliseconds(2000)); threads[i] = std::thread(print_id, i); } std::cout << "5 threads ready to race...\n"; go(); // go! for (auto& th : threads) th.join(); return 0; }
内容的提问来源于stack exchange,提问作者Azzurro94
相关产品推荐
相关产品推荐

