2013-08-06 3 views
0

Мы говорили о функции и многопоточности с моим другом. Код примера:Mutex и встроенная функция

void SomeClass::Foo() 
{ 
    std::lock_guard<std::mutex> lock(mMutexObj); 

    statement1; 
    statement2; 
    statement3; 
} 

Итак, мы знаем, что иногда компилятор строит функции там, где это необходимо. Можно ли в таком случае: компилятор встраивает функции Foo, все 3 заявления запуска и lock_guard не работает, потому что сфера применения не заканчивается и не деструктор не называется:

// Inlined operations 
std::lock_guard<std::mutex> lock(mMutexObj); 

statement1; 
statement2; 
statement3; 

// Global scope, where function was inlined continues here... 
global statement1; 
global statement2; 
...; 

Возможно ли это? Какой процент этот компилятор будет встроить в такую ​​функцию, или, может быть, я не понимаю, в какой степени встроена функция?

+0

Есть ли в подкладке разрешено изменять объем? Я всегда предполагал, что он добавляет '{' и '}' вокруг того, что было скопировано вокруг ... –

+0

@ebyrob Я думаю, что изменение сферы действия приведет к хаосу. Использование #defines сделало бы это. Я думаю, что одна из причин для создания функций - это избежать проблем, вызванных #defines – maditya

ответ

9

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

3

Эффект, который вы описываете, произойдет, если вы будете использовать #define s/macros, но не используете inline. На самом деле, я считаю, что одна из причин, по которой была введена инкрустация, заключалась в том, чтобы избежать резни, вызванной неправильным использованием #define.

Я считаю, что область действия сохраняется, используя метод, эквивалентный использованию { и }.

// Inlined operations 
{ //curly braces create a scope 
    std::lock_guard<std::mutex> lock(mMutexObj); 

    statement1; 
    statement2; 
    statement3; 
} 

// Global scope 
global statement1; 
global statement2; 
...; 

Обратите внимание на использование фигурных скобок сверху. Это вполне допустимый код, и я стараюсь использовать его, когда мне нужно блокировать/разблокировать мьютекс в нескольких точках в пределах одной функции. Я думаю, что компилятор делает что-то подобное с встроенными функциями.

2

Просто, чтобы ответить на вопрос о том, «какой процент компиляторов будет встроен в нечто подобное». Учитывая сборку «выпуска» (то есть сборку с высоким уровнем оптимизации), я ожидал бы, что все современные высококачественные компиляторы составят этот код, предполагая, что statement не разрешает что-то ОЧЕНЬ большое (например, в свою очередь, встраивая функцию который встраивает другую функцию, которая строит третью функцию).

Я знаю, что GCC будет встроить статическую функцию, которая вызывается только один раз, даже если она ОГРОМНАЯ, потому что она по существу удаляет несколько инструкций, даже если вся «базовая» функция получает несколько килобайт больше.

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

И, конечно же, виртуальные функции не вставляются, если только они не «очевидны» тем, что является объектом.

Смежные вопросы