2

如果多个线程共享一个指向同一个对象的指针,那么调用它的虚方法是否安全?当然我们应该假设方法本身是线程安全的。

class Base {
public:
  virtual int test(int arg) = 0;
};

class Derived1: public Base {
public:
  virtual int test(int arg) { return arg * 2; }
};

class Derived2: public Base {
public:
  virtual int test(int arg) { return arg * 3; }
};

//call in threads:
Base* base = (pointer to the same Derived1);
int value = base->test(1);
4

5 回答 5

2

是的,这很好,只要对象的生命周期*base超过函数调用的生命周期。

于 2013-02-07T14:29:50.783 回答
1

调用虚函数通常是通过在类中查找 vtable 条目来实现的。这个 vtable 不会改变,所以对于这个实现,它应该是线程安全的。

我不认为有一个普遍的保证。

于 2013-02-07T14:30:57.120 回答
1

根据“Kerrek SB 对先前答案的评论,我已经开始了大约三遍这个答案。在我看来,没有阅读规范直到我的眼睛流血,我不确定什么不应该是虚拟线程安全的call - “虚拟函数选择”(vtable 或任何它可能是)的实现绝对不会引起任何问题,因为它应该只是指向函数的指针,它基于索引 [或类似的] 被调用选择的功能。

对不起,这不是答案,但我很难看到任何情况,在我知道它是如何工作的任何处理器上(x86、68K、29k、ARM 是我已经足够使用的处理器)了解如何在汇编程序中实现虚函数)由于线程而出错 - 假设其他代码是安全的 - 如果在上面的示例中我们要运行第二个线程来修改哪些元素base指向,你可能有一些某种竞争条件,其中 base 的值指向错误的虚函数集,或类似的。但这不是调用本身,而是修改base“非线程安全”的代码。

当然,可能有一些“业余”编译器以其他方式解决虚函数。

当然,如果出现问题 - 除非您在整个虚拟调用期间阻塞其他线程 - 并且如果您有一个通过将虚拟函数run(void *args)作为“this是在线程内运行的内容”,这是我见过几次的东西,这几乎会完全杀死该功能!

所以,基本上,虽然我无法参考说明这是安全的规范部分,但除了“它必须是”之外,我看不到任何解决方案。

于 2013-02-07T14:49:22.473 回答
0

如果该方法是线程安全的,那就没问题了。

于 2013-02-07T14:31:16.457 回答
0

简而言之:如果不是,C++ 将根本无法用于多线程编程。

长篇:

  1. 编译后程序是不变的。所以它的线程安全。

  2. 在加载(模块)时,运行时系统会更改 RTTI 的数据结构(dynamic_cast,...)。这超出了您的范围,但应该以线程安全的方式实现。

  3. 构造后,对象的类型不会改变(您可以使用非常肮脏的技巧)。所以你所有对象的所有虚函数都不应该改变。所以它的线程安全。

但是您应该考虑到可以被视为虚拟函数(boost 函数,loki 函子,...)的替代的类成员可能具有值语义并且可以在调用时更改。在这种情况下,它应该被记录在案或者应该实现更好的使用它们的接口。

在我看来,您可以安全地调用虚拟方法。即使在有人尝试模仿虚函数的情况下,您也可以期待正常(安全)的行为。

于 2013-02-07T15:14:56.037 回答