Виртуальный метод называется потокобезопасным?

Если несколько потоков совместно используют указатель на один и тот же объект, безопасно ли вызывать его виртуальный метод? Конечно, мы должны предположить, что сам метод является потокобезопасным.

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);
1
Разве это не так, что вы рекомендуете в качестве рабочего? Я не понимаю, почему это не должно быть безопасно - Java делает это каждый день.
добавлено автор John Dvorak, источник
Конечно, вызов указателя функции при изменении указателя - это совсем другой вопрос (все еще безопасный ИМО). То же самое относится к вызовам методов, в которых разыменованный объект может измениться. Конечно, все они совершенно безопасны в Java :-)
добавлено автор John Dvorak, источник
IOW, я бы использовал его без колебаний, но у меня нет документов, чтобы поддержать меня.
добавлено автор John Dvorak, источник

5 ответы

Да, это нормально, если срок службы объекта * base превышает срок службы вызова функции.

1
добавлено
Это важная вещь. Динамический тип объекта не изменяется в течение его жизни: с момента завершения конструктором его работы до момента начала деструктора. Однако при строительстве и это происходит, что является удивительным поведением (хотя и нормальным).
добавлено автор Matthieu M., источник

Я начал этот ответ примерно три раза, основываясь на комментарии «Kerrek SB» по предыдущему ответу. Как я вижу, без чтения спецификаций, пока мои глаза не истекают кровью, я не уверен, что не должно быть поточным виртуальным вызов - реализация «выбора виртуальных функций» (vtable или что-то еще, что может быть) должна определенно не вызвать никаких проблем, поскольку она должна быть просто указателем на функцию, которая вызывается на основе индекса [или аналогичного] функция выбрана.

Извините, это не ответ, но мне очень трудно увидеть любой сценарий на любом процессоре, который я знаю, как он работает (x86, 68K, 29k, ARM - это те, над которыми я работал достаточно, чтобы понять, как виртуальная функция реализована на ассемблере), где это пойдет не так из-за потоков - если другой код будет безопасным - если в приведенном выше примере мы должны были запустить второй поток, который изменяет какой элемент base точки, вы могли бы иметь какое-то гоночное состояние, где значение базы указывает на неправильный набор виртуальных функций или на некоторые из них. Но это не сам вызов, а код, изменяющий base , который не является потокобезопасным.

Конечно, может быть некоторый «любительский» компилятор, который решает виртуальные функции каким-то другим способом.

Разумеется, не было бы разумного обходного пути, если бы была проблема - если только вы не блокируете другие потоки в течение всего времени виртуального вызова, - и если у вас есть класс, который реализует потоки с помощью виртуальной функции run (void * args) как «это то, что нужно запускать внутри потока», что я уже несколько раз видел, и это полностью уничтожило бы эту функциональность!

Итак, в основном, хотя я не могу ссылаться на раздел спецификации, в котором говорится, что это безопасно, я не вижу никакого решения, кроме «он должен быть».

1
добавлено
Что же касается стандартной ссылки: в стандарте говорится, какие типы действий вводят гонку данных, а отправка виртуальной функции не является одним из них.
добавлено автор Kerrek SB, источник

Вызов виртуальных функций обычно осуществляется путем поиска записи vtable в классе. Этот vtable не изменяется, поэтому для этой реализации он должен быть потокобезопасным.

Я не думаю, что есть общая гарантия.

1
добавлено
Было бы неплохо получить ответ от языка, который не зависит от деталей реализации.
добавлено автор Kerrek SB, источник

Вкратце: Если нет, C ++ не будет использоваться вообще для многопоточного программирования.

В долгосрочной перспективе:

  1. После компиляции программа является постоянной. Так что его поток безопасен.

  2. При загрузке (модулей) система времени выполнения изменяет структуры данных для RTTI (dynamic_cast, ...). Это выходит за рамки вашего приложения, но оно должно быть реализовано безопасным потоком.

  3. После построения тип вашего объекта не изменяется (вы можете с очень грязными трюками). Таким образом, все виртуальные функции всех ваших объектов не должны меняться. Так что его поток безопасен.

Но вы должны учитывать, что член классов, который можно рассматривать как замену для виртуальных функций (функция boost, loki functor, ...), может иметь семантику значений и может меняться при вызове. В этом случае он должен быть документирован или лучше использовать интерфейс для их использования.

На мой взгляд, вы можете безопасно вызвать виртуальный метод. Даже в том случае, если кто-то использует попытки имитировать виртуальные функции, вы можете ожидать нормального (безопасного) поведения.

0
добавлено

Если метод является потокобезопасным, то это нормально.

0
добавлено
pro.cxx
pro.cxx
3 049 участник(ов)

C/C++ chat 0. Простые вопросы, лабы и о IDE — в чат новичков @supapro 1. Не хамим, не переходим на личности, не вбрасываем утверждения без доказательств 2. No Ads, offtop, flood Объявления о вакансиях и евенты - в лс @AlexFails https://t.me/ProCxx/259155

supapro.cxx
supapro.cxx
1 925 участник(ов)

Чат для тех, кто немного знает C++, простые вопросы по реализации, синтаксису и ide – сюда, а для другого есть: /Главный чат по серьезным вопросам — @ProCxx /Чат по обсуждению всего — @fludpac

C++ Russia
C++ Russia
384 участник(ов)

Сообщество разработчиков C++ в Telegram.

cxx.Дискуссионная
cxx.Дискуссионная
298 участник(ов)

это не двач, общайтесь вежливо; разговор на почти любые темы; Не согласны с баном? В лс @AlexFails, @ivario

C++ для маленьких и тупых
C++ для маленьких и тупых
105 участник(ов)

Лоу левел (по среднему IQ участников) чатик ExtremeCode @extremecode Флудилка @extremecode_rest