C++ 为什么父母';s方法在child';毁灭
我不明白为什么要运行父类的“execute”函数。我觉得有两个实例:一个用于父类,一个用于子类,但是为什么呢?实际上,这个程序正在打印“1个家长”,正如我预期的“1个孩子”或“0个家长”。如果我取消对延迟线的注释,输出将是“1个子” 我知道这个节目中有一个比赛条件。这个程序只是为了理解多线程环境中继承的工作原理 谢谢大家!C++ 为什么父母';s方法在child';毁灭,c++,multithreading,inheritance,race-condition,C++,Multithreading,Inheritance,Race Condition,我不明白为什么要运行父类的“execute”函数。我觉得有两个实例:一个用于父类,一个用于子类,但是为什么呢?实际上,这个程序正在打印“1个家长”,正如我预期的“1个孩子”或“0个家长”。如果我取消对延迟线的注释,输出将是“1个子” 我知道这个节目中有一个比赛条件。这个程序只是为了理解多线程环境中继承的工作原理 谢谢大家! #include <stdio.h> #include <stdlib.h> #include <iostream> #include &
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <thread>
class Parent
{
public:
std::thread myThread;
int a;
Parent() {
this->myThread = std::thread();
this->a = 0;
}
void start()
{
this->myThread = std::thread(&Parent::execute, this);
}
virtual void execute() {
std::cout << a << " Parent" << std::endl;
}
virtual ~Parent() {
while(!this->myThread.joinable());
this->myThread.join();
}
};
class Child : public Parent
{
public:
Child() {
this->a = 1;
}
void execute() override {
std::cout << a << " Child" << std::endl;
}
~Child() {
}
};
int main()
{
std::cout << "Init" << std::endl;
Child * chld = new Child();
chld->start();
//std::this_thread::sleep_for(std::chrono::milliseconds(x));
std::cout << "Delete" << std::endl;
delete chld;
return 0;
}
#包括
#包括
#包括
#包括
#包括
班级家长
{
公众:
线程读取;
INTA;
父项(){
这->myThread=std::thread();
这->a=0;
}
void start()
{
this->myThread=std::thread(&Parent::execute,this);
}
虚拟空执行(){
标准::cout a=1;
}
void execute()重写{
std::cout您的程序有未定义的行为,这意味着“一切都可能发生”
您启动一个新线程,该线程持有指向对象的指针(this)。该线程稍后将调用一个虚拟方法,这意味着它需要使用它指向的对象中的数据。vtable指针本身是类的某种数据。因为您从另一个线程中删除了对象,指针(this)只是指向已破坏的对象并从已删除的对象访问数据(vtable)是未定义的行为
您的观察结果取决于编译器实现,也可能取决于优化级别。在解构过程中,您的编译器可能会将vtable指针倒回基类指针。而且,对象的内存不会被任何其他内容覆盖(甚至是未定义的内容!)您可以在销毁后观察对基函数的调用。但这不是您可以依赖的,因为如果您使用对象的数据成员(此处为vtable指针),则在销毁后根本不允许使用任何对象
简而言之:您的代码包含一个bug,任何事情都可能发生,因为它是未定义的行为。这与线程无关。您可以同步复制整个过程,包括未定义的行为
类的单线程版本:
#include <iostream>
#include <string>
class Parent
{
public:
int a;
Parent() : a(0) {}
virtual ~Parent() {}
virtual void execute() {
std::cout << a << " Parent" << std::endl;
}
};
class Child : public Parent
{
public:
Child() {
a = 1;
}
void execute() override {
std::cout << a << " Child" << std::endl;
}
};
您的代码显示未定义的行为(在您的情况下导致Parent::execute
调用)由于线程创建和子对象
对象销毁之间存在争用条件。若要解决此问题,您可以在父类
中定义正确的启动和停止方法,并在子对象
析构函数中调用停止
,以防止在线程联接之前将其销毁
class Parent
{
public:
Parent(): myThread_() {
std::cout << "Parent CTor" << std::endl;
}
virtual ~Parent() = default;
bool start()
{
std::cout << "start" << std::endl;
if (myThread_.joinable()) {
std::cout << "already started" << std::endl;
return false;
}
myThread_ = std::thread([this]() {
execute();
});
return true;
}
bool stop() {
std::cout << "stop" << std::endl;
if (!myThread_.joinable()) {
std::cout << "not started" << std::endl;
return false;
}
myThread_.join();
return true;
}
virtual void execute() = 0;
private:
std::thread myThread_;
};
class Child : public Parent
{
public:
Child() {
std::cout << "Child CTor" << std::endl;
}
~Child() override {
stop();
}
void execute() override {
std::cout << "Child::execute()" << std::endl;
}
};
int main()
{
std::cout << "Init" << std::endl;
Child * chld = new Child();
chld->start();
std::cout << "Delete" << std::endl;
delete chld;
return 0;
}
Parent::execute()
仍然调用父函数。不总是这样,如果在开始和删除之间设置延迟,则将调用Child::execute()
functionThreading在这里不起任何作用。如果您的writeParent::execute
显式地告诉您要调用哪个函数,而不是让运行时解析虚拟函数调用。我昨天看到了完全相同的问题,但它似乎被删除了。我还解释了这是一个reace条件,因为子级被删除。@FrançoisAndrieux尝试使用我注释的延迟执行函数,它将执行子函数,因为函数重写。这实际上不一样,因为在我的代码中对象没有被销毁,因为主线程正在等待第二个线程加入。我错了吗?如果子析构函数在线程I之前已经执行了如果已计划,则在阻止父析构函数的同时,对其动态类型已回滚到父类的对象调用该方法。这就是您感兴趣的情况吗?因为在这种情况下,您有一个父对象,其a
仍然具有子构造函数给定的值1
。线程仍然是ir相关,因为您可以通过从基类析构函数调用重写的虚拟方法来查看此行为。
=== automatic lifetime ===
virtual dispatch: 1 Child
explicit static dispatch: 1 Parent
=== dynamic lifetime ===
virtual dispatch: 1 Child
explicit static dispatch: 1 Parent
=== undefined behaviour ===
explicit static dispatch: 1 Parent
Segmentation fault (core dumped) ./a.out
class Parent
{
public:
Parent(): myThread_() {
std::cout << "Parent CTor" << std::endl;
}
virtual ~Parent() = default;
bool start()
{
std::cout << "start" << std::endl;
if (myThread_.joinable()) {
std::cout << "already started" << std::endl;
return false;
}
myThread_ = std::thread([this]() {
execute();
});
return true;
}
bool stop() {
std::cout << "stop" << std::endl;
if (!myThread_.joinable()) {
std::cout << "not started" << std::endl;
return false;
}
myThread_.join();
return true;
}
virtual void execute() = 0;
private:
std::thread myThread_;
};
class Child : public Parent
{
public:
Child() {
std::cout << "Child CTor" << std::endl;
}
~Child() override {
stop();
}
void execute() override {
std::cout << "Child::execute()" << std::endl;
}
};
int main()
{
std::cout << "Init" << std::endl;
Child * chld = new Child();
chld->start();
std::cout << "Delete" << std::endl;
delete chld;
return 0;
}
terminate, pure virtual method called