为啥 std::unique_lock 改变 std::unique_ptr?
Posted
技术标签:
【中文标题】为啥 std::unique_lock 改变 std::unique_ptr?【英文标题】:Why std::unique_lock changes std::unique_ptr?为什么 std::unique_lock 改变 std::unique_ptr? 【发布时间】:2020-04-14 19:17:19 【问题描述】:这里发生了一些奇怪的事情,至少对我来说很奇怪......
我有一个线程函数...
void run(std::mutex &mtx, std::condition_variable &cv)
std::unique_ptr<float[]> shiftbuf(new float[SHIFTBUF_SIZE]);
float *const shiftbuf_p = shiftbuf.get();
for (;;)
*(shiftbuf_p + SHIFTBUF_SIZE - 1) = 100.f;
std::unique_lock<std::mutex> lck(mtx);
cv.notify_all();
主要是...
std::mutex mtx;
std::condition_variable cv;
std::thread th(run, std::ref(mtx), std::ref(cv));
std::unique_lock<std::mutex> lck(mtx);
cv.wait(lck);
当我调试代码并观察shiftbuf_p
时,lck
上的地址更改?!
Thread 18 "..." hit Hardware watchpoint 4: shiftbuf_p
Old value = (float * const) 0x7fffd8000b10
New value = (float * const) 0x7fffd8000b01
run (mtx=..., cv_second=..., amplitude_data=..., tm=...)
at ....cpp:132
132 std::unique_lock<std::mutex> lck(mtx);
(gdb) c
Continuing.
Thread 18 "..." hit Hardware watchpoint 4: shiftbuf_p
Old value = (float * const) 0x7fffd8000b01
New value = (float * const) 0x7fffd8000001
run (mtx=..., cv_second=..., amplitude_data=..., tm=...)
at ....cpp:132
132 std::unique_lock<std::mutex> lck(mtx);
(gdb) c
Continuing.
Thread 18 "..." hit Hardware watchpoint 5: shiftbuf_p
Old value = (float * const) 0x7fffd8000001
New value = (float * const) 0x7fff00000001
run (mtx=..., cv_second=..., amplitude_data=..., tm=...)
at ....cpp:132
132 std::unique_lock<std::mutex> lck(mtx);
(gdb) c
Continuing.
Thread 18 "..." received signal SIGSEGV, Segmentation fault.
而且它永远不会变回到正确的原始地址。
当run()
继续时shiftbuf_p
指向错误的地址。
为什么地址会改变?它是一个常量指针。 unique_ptr 范围在子线程中是顶部的。等待调用在主线程中。
但shiftbuf.get()
也会返回nullptr
。就像 unique_ptr shiftbuf
超出范围,但这段代码不应该发生这种情况,不是吗?
你能解释一下发生了什么吗?
【问题讨论】:
请提供一个至少可以编译的最小可复制示例 是否启用优化? 可能shiftbuf_p
变量被优化为未使用,而空间被重新用于lck
。
std::condition_variable cv; cv.wait(lck);
这没有意义,您正在等待本地创建的 cv 并且您的线程正在通知其他一些 cv(您没有显示另一个来自哪里)
std::unique_ptr<float> shiftbuf(new float[SHIFTBUF_SIZE]);
错误,这里需要使用数组专用的unique_ptr
。 std::unique_ptr<float[]> shiftbuf(new float[SHIFTBUF_SIZE]);
【参考方案1】:
好的。我想我找到了我的问题。
堆栈上还有另一个数据数组,这个数组被用来写越界,因为它的索引完全失控了。
因此shiftbuf_p
地址可能会更改。
很难找到...没有 -fstack-protector 或 valgrind 检测到原因。
【讨论】:
-fstack-protector
只能防止堆栈 frame 溢出(即当损坏落后于 all 局部变量时),并且只能在返回时。不确定valgrind
,但它针对的是堆分配AFAIK。以上是关于为啥 std::unique_lock 改变 std::unique_ptr?的主要内容,如果未能解决你的问题,请参考以下文章
linux C++互斥锁std::lock_guard(轻锁)std::unique_lock(重锁)区别