Встроенные функции членства в C++

Synchronized normal method, эквивалентный Synchronized statement (используйте это)

class A {
    public synchronized void methodA() {
        // all function code
    }

    equivalent to

    public void methodA() {
        synchronized(this) {
             // all function code
        }
    } 
}

Synchronized static method, эквивалентный Synchronized statement (использовать класс)

class A {
    public static synchronized void methodA() {
        // all function code
    }

    equivalent to

    public void methodA() {
        synchronized(A.class) {
             // all function code
        }
    } 
}

Синхронизированный оператор ( используя переменную)

class A {
    private Object lock1 = new Object();

    public void methodA() {
        synchronized(lock1 ) {
             // all function code
        }
    } 
}

Для synchronized мы имеем оба Synchronized Methods и Synchronized Statements. Однако Synchronized Methods подобен Synchronized Statements, поэтому нам просто нужно понять Synchronized Statements.

=> В принципе, мы будем иметь

synchronized(object or class) { // object/class use to provides the intrinsic lock
   // code 
}

. Здесь 2 считают, что help synchronized

  • У каждого объекта / класса есть intrinsic lock, связанный с ним.
  • Когда поток вызывает synchronized statement, он автоматически получает intrinsic lock для этого объекта synchronized statement's и освобождает его при возврате метода. Пока нить принадлежит intrinsic lock, ни один другой поток не может получить SAME lock => thread safe.

=> Когда thread A вызывает synchronized(this){// code 1} => все блочный код (внутри класса), где synchronized(this) и все synchronized normal method (внутри класса) заблокированы, потому что SAME заблокирован. Он будет выполнен после разблокировки thread A («// код 1» завершен).

Это поведение похоже на synchronized(a variable){// code 1} или synchronized(class).

SAME LOCK => lock (не зависит от какого метода? или каких операторов?)

Использовать синхронизированный метод или синхронизированные операторы?

Я предпочитаю synchronized statements потому что он более расширяем. Например, в будущем вам потребуется только синхронизация части метода. Например, у вас есть 2 синхронизированный метод, и он не имеет никакого отношения друг к другу, однако, когда поток запускает метод, он блокирует другой метод (он может предотвратить использование synchronized(a variable)).

Однако применять синхронный метод просто и код выглядит просто. Для некоторого класса существует только один синхронизированный метод или все синхронизированные методы в классе, относящиеся друг к другу => мы можем использовать synchronized method, чтобы сделать код короче и легко понятным

Примечание

(это мало относится к synchronized, оно отличается от объекта и класса или нестатического и статического).

  • Когда вы используете synchronized или обычный метод, или synchronized(this) или synchronized(non-static variable), он будет синхронизироваться с базой на каждом экземпляре объекта.
  • Когда вы используете synchronized или статический метод или synchronized(class) или synchronized(static variable), он будет синхронизирован базой в классе

Ссылка

https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync. html

Надеюсь, что это поможет

14
задан EFraim 2 March 2009 в 20:12
поделиться

5 ответов

Когда у Вас есть встроенный метод, который вынужден быть невстроенным компилятором, он действительно инстанцирует метода в каждой скомпилированной единице, которая использует его. Сегодня большинство компиляторов достаточно умно для инстанцирования метода, только если необходимый (если используется) так просто включая заголовочный файл не вызовет инстанцирование. Компоновщик, как Вы сказали, выберет одно из инстанцирований для включения в исполняемый файл - но иметь в виду, что запись в объектном модуле является специальным видом (например, COMDEF), чтобы дать компоновщику достаточно информации, чтобы знать, как отбросить дублированные экземпляры. Эти записи, поэтому, не приведут к нежелательным зависимостям между модулями, потому что компоновщик будет использовать их с меньшим приоритетом, чем "регулярные" записи для разрешения зависимостей.

В примере Вы дали, Вы действительно не знаете, но он не имеет значения. Компоновщик не разрешит зависимости на основе одних только невстроенных экземпляров никогда. Результат (с точки зрения модулей, включенных компоновщиком), будет так же хорош, как будто встроенный метод не существовал.

7
ответ дан 1 December 2019 в 12:14
поделиться

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

C++

До Стандартного C++ затронут, подставляемая функция должна быть определенной в каждой единице перевода, в которой это используется. И нестатическая подставляемая функция будет иметь те же статические переменные в каждой единице перевода и тот же адрес. Компилятор/компоновщик должен будет объединить повторные определения в одну функцию для достижения этого. Так, всегда поместите определение подставляемой функции в заголовок - или не поместите объявление его в заголовок при определении его только в файле реализации (" .cpp") (для не являющейся членом функции), потому что, если бы Вы были бы, и кто-то использовал его, Вы получили бы ошибку компоновщика о неопределенной функции или чем-то подобном.

Это отличается от неподставляемых функций, которые должны быть определены только однажды во всей программе ( одно правило определения ). Для подставляемых функций повторные определения, как обрисовано в общих чертах выше являются скорее нормальным случаем. И это независимо на том, встраивается ли вызов atually или нет. Правила о подставляемых функциях все еще имеют значение. Придерживается ли компилятор Microsoft тех правил или не - я не могу сказать Вам. Если это будет придерживаться Стандарта в том отношении, то это будет. Однако я мог вообразить некоторую комбинацию, использующую виртуальный, dlls, и другой TUs мог быть проблематичным. Я никогда не тестировал его, но я полагаю, что нет никаких проблем.

Для функций членства при определении функции в классе это неявно встроено. И потому что это появляется в заголовке, правило, что это должно быть определено в каждой единице перевода, в которой это используется, автоматически удовлетворено. Однако при определении функции из класса и в заголовочном файле (например, потому что существует круговая зависимость с промежуточным кодом), тогда то определение должно быть встроено при включении соответствующего файла несколько раз, для предотвращения ошибок повторного определения, брошенных компоновщиком. Пример файла f.h:

struct f {
    // inline required here or before the definition below
    inline void g();
};

void f::g() { ... }

Это имело бы тот же эффект как размещение определения прямо в определение класса.

Примечание C99

, что правила о подставляемых функциях более сложны для C99, чем для C++. Здесь, подставляемая функция может быть определена как встроенное определение , которого может существовать больше чем один во всей программе. Но если такой (встроенный-) определение используется (например, если это называют), тогда там должен быть также точно один внешнее определение во всей программе, содержавшейся в другой единице перевода. Объяснение для этого (заключающий в кавычки из PDF, объясняющего объяснение позади нескольких функций C99):

Встраивание в C99 действительно расширяет спецификацию C++ двумя способами. Во-первых, если функция объявляется встроенная в одной единице перевода, она не должна быть объявлена встроенная в любой единице перевода. Это позволяет, например, библиотечную функцию, которая должна быть встроена в библиотеке, но доступная только через внешнее определение в другом месте. Альтернатива для использования функции обертки для внешней функции требует дополнительного имени; и это может также неблагоприятно повлиять на производительность, если переводчик на самом деле не делает встроенной замены.

1118-секундный, требование, чтобы все определения подставляемой функции быть "точно тем же" были заменены требованием, чтобы поведение программы не зависело от того, реализован ли вызов с видимым встроенным определением или внешним определением, функции. Это позволяет встроенному определению быть специализированным для его использования в конкретной единице перевода. Например, внешнее определение библиотечной функции могло бы включать некоторую проверку аргумента, которая не нужна для вызовов, выполненных от других функций в той же библиотеке. Эти расширения действительно предлагают некоторые преимущества; и программисты, которые обеспокоены совместимостью, могут просто соблюдать более строгие правила C++.

, Почему я включаю C99 в здесь? Поскольку я знаю, что компилятор Microsoft поддерживает некоторый материал C99. Таким образом на тех страницах MSDN, некоторый материал может прибыть из C99 также - ничего не изобразили в особенности все же. Нужно быть осторожным при чтении его и при применении тех методов к, собственный код C++ намеревался быть портативным C++. Вероятно, информирование, какие части C99 конкретный, и который нет.

А хорошее место для тестирования маленьких отрывков C++ на Стандартное соответствие comeau компилятор онлайн . Если это отклоняется, можно быть вполне уверенным, это не строго Стандартное приспосабливание.

8
ответ дан 1 December 2019 в 12:14
поделиться

Не встраивайте свои функции, если Вы хотите удостовериться, что они компилируются в определенную библиотеку.

2
ответ дан 1 December 2019 в 12:14
поделиться

AFAIK, нет никакого стандартного определения того, как и когда компилятор C++ встроит вызов функции. Это обычно "рекомендации", за которыми компилятор никоим образом не требуется, чтобы следовать. На самом деле различные пользователи могут хотеть различные поведения. Один пользователь может заботиться о скорости, в то время как другой может заботиться о небольшом сгенерированном размере объектного файла. Кроме того, компиляторы и платформы отличаются. Некоторые компиляторы могут применить более умный анализ, некоторые не могут. Некоторые компиляторы могут сгенерировать более длинный код от встроенного, или работать над платформой, где вызовы являются слишком дорогими, и т.д.

, Когда у Вас есть подставляемая функция, компилятор должен все еще генерировать символ для него и в конечном счете разрешить единственную версию его. Так, чтобы, если это находится в статической библиотеке, люди могли все еще вызвать функцию не во встроенном. Другими словами, это все еще действует как нормальная функция.

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

4
ответ дан 1 December 2019 в 12:14
поделиться

, Если компилятор решил создать символ для той функции (и в этом случае, это будет из-за 'виртуальности', будет несколько (внешне замеченных) инстанцирований в другом объектном файле, который определение (от который объектный файл?) компоновщик выберет?)

определение, которое присутствует в соответствующей единице перевода. И единица перевода не может, и я повторяюсь, не может иметь, но точно одно такое определение. Стандарт соглашается с этим.

[...] компоновщик мог бы "выбрать" файл произвольного объекта как источник для определения.

РЕДАКТИРОВАНИЕ: , Чтобы постараться не дальше неправильно понимать, позвольте мне высказать свое ясное мнение: Согласно моему чтению стандарта, способность иметь повторное определение через другой TUs не дает нам никакой практическое воздействие. Практическим я означаю иметь даже немного переменные реализации. Теперь, если все Ваши TUs имеют то же самое определение, почему беспокойство, от которого поднимается TU определение?

, Если Вы просматриваете стандарт, Вы найдете, что Одно Правило Определения применяется везде. Даже при том, что это , позволил иметь повторные определения inline функция:

3.2 Одно Правила Определения:

5 может быть больше чем одно определение типа класса (Пункт 9), понятие (14.9), карта (14.9.2) понятия, перечисляемый тип (7.2), подставляемая функция с внешней связью (7.1.2), [...]

Read это в сочетании с [1 133]

3 [...] подставляемая функция должна быть определена в каждой единице перевода, в которой это используется.

Это означает, что функция будет определена в каждой единице компиляции [...]

и

7.1.2 Функциональных Спецификатора

объявление функции, на 2 А (8.3.5, 9.3, 11.4) со встроенным спецификатором объявляет подставляемую функцию. Встроенный спецификатор указывает к реализации, что встроенная замена тела функции при вызове должна быть предпочтена обычному механизму вызова функции. Реализация не требуется, чтобы выполнять эту встроенную замену при вызове; однако, даже если эта встроенная замена будет опущена, то другие правила для подставляемых функций, определенных 7.1.2, нужно все еще уважать.

функция, определяемая на 3 А в рамках определения класса является подставляемой функцией. Встроенный спецификатор не должен появляться на объявлении функции области действия блока. [сноска: 82], Если встроенный спецификатор используется в друге объявление, то объявление должно быть определением, или функция должна быть ранее объявлена встроенная.

и сноска:

82), встроенное ключевое слово не имеет никакого эффекта на связь функции. В§ 7.1.2 138

, а также:

4 подставляемая функция должна быть определена в каждой единице перевода, в которой она используется и должна иметь точно то же определение в каждом случае (3.2). [Отметьте: с вызовом к подставляемой функции можно встретиться, прежде чем ее определение появляется в единице перевода. — заканчивают примечание], Если определение функции появляется в единице перевода, прежде чем ее первое объявление как встроенное, программа будет плохо сформирована. Если функция с внешней связью будет объявлена встроенная в одной единице перевода, то она должна быть объявлена встроенная во всех единицах перевода, в которых это появляется; никакая диагностика не требуется. Подставляемая функция с внешней связью должна иметь тот же адрес во всех единицах перевода. Статическая локальная переменная в подставляемой функции экстерна всегда относится к тому же объекту. Строковый литерал в теле подставляемой функции экстерна является тем же объектом в различных единицах перевода. [Отметьте: строковый литерал, появляющийся в выражении параметра по умолчанию, не находится в теле подставляемой функции просто, потому что выражение используется в вызове функции от той подставляемой функции. — заканчивают примечание]

Дистиллированный: хорошо, чтобы иметь повторные определения, но у них должен быть тот же стиль в [1 158] каждый единица перевода и адрес - но это действительно не дает Вам очень для приветствия о. Наличие нескольких deinition через единицы перевода поэтому не определено (примечание: Я не говорю, что Вы вызов UB, все же).

Что касается virtual штука - не будет никакого встраивания. Период.

в стандарте говорится:

  • тот же объявление должно быть доступно
  • должно быть одно определение

От [1 111] MSDN:

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

Ваш A.h содержит определение класса и участника foo() определение.

U1.cpp и U2.cpp оба определяют два различных объекты из класса A.

, Вы создаете другой A объект в main(). Это очень хорошо.

До сих пор, я видел только одно определение A::foo(), который встроен. (Помните, что функция, определяемая в рамках объявления класса всегда , встроил, предшествуют ли этому inline ключевое слово.)

3
ответ дан 1 December 2019 в 12:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: