如果
ipc
在单独的线程上调用 lambda,那么这段代码中是否存在数据竞争?如果 vtable 尚未完全构建,那么 lambda 可能会调用 Base::Handle()
,但如果是的话,它将调用 Derived::Handle()
,对吧?
#include <thread>
#include <chrono>
#include <functional>
#include <iostream>
#include <mutex>
#include <condition_variable>
struct IPC {
IPC() : t([&]{
std::unique_lock lk(mut);
cv.wait(lk, [&]{ return (bool)f; });
f();
}) {}
void SetHandler(std::function<void()> f_) {
{
std::unique_lock lk(mut);
f = f_;
}
cv.notify_all();
}
std::mutex mut;
std::condition_variable cv;
std::function<void()> f;
std::thread t;
};
struct Base {
Base() {
ipc.SetHandler([this]{ Handle(); });
// Maybe construction of Base takes some time.
// Removing this sleep makes the output of the program stabilize on "Derived".
std::this_thread::sleep_for(std::chrono::microseconds(10));
}
virtual void Handle() { std::cout << "Base" << std::endl; }
IPC ipc;
};
struct Derived : Base {
void Handle() override { std::cout << "Derived" << std::endl; }
};
int main()
{
Derived b;
// I only care about interaction with constructors so join here
// to delay destruction of b until the test is finished.
b.ipc.t.join();
}
在我的笔记本电脑上连续多次运行此代码会产生“Base”和“Derived”随机交替的输出。
developer@WDX591VWD3:~$ g++-10 -std=c++20 hi.cpp -lpthread
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Derived
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Derived
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Derived
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Base
developer@WDX591VWD3:~$ ./a.out
Derived
developer@WDX591VWD3:~$
所以我想问题是:这是未定义的行为吗?在 IPC 能够调用处理程序以便调用派生类处理程序之前,我需要等待多长时间?我需要进行任何同步吗?
这将产生未定义的行为。
虽然我认为该标准目前缺乏一些措辞,但我认为只有在最派生对象的构造完成后才可以在另一个线程中使用该对象。
当尝试通过不是从 this
派生的指针访问对象时,
[class.cdtor]/2中给出了类似的规定。
我还希望类是否是多态的并不重要。上面链接的限制也不仅仅适用于多态类。