Является ли выполнение `_dl_init` (инициализация программы) однопоточным в C / C ++? - PullRequest
1 голос
/ 20 февраля 2020

У меня есть несколько исходных файлов C ++, в которых некоторые данные / обратные вызовы зарегистрированы на карте в заголовке.

// foo.h

class Foo final {
public:
    static void Register(...) { ... }

private:
    inline static std::map<...> g_map{};
};

// a.cc, b.cc, etc.

#include "foo.h"

namespace {

struct Init {
    Init() {
        Foo::Register(...);
    }
};

Init g_init{}; // the inversion-of-control trick

}

Так необходимо ли использовать блокировки для защиты g_map? Моя интуиция заключается в том, что выполнение _dl_init (вызов времени выполнения, предшествующий main) является однопоточным, хотя порядок a.cc, b.cc, ... неизвестен, я прав?

1 Ответ

1 голос
/ 20 февраля 2020

Если переменные non local stati c инициализируются перед запуском основного, они будут инициализированы в потоке, определенном в [basi c .start.main] (см. Черновик n4659 для C ++ 20):

Выполнение программы запускает основной поток выполнения (4.7, 33.3), в котором вызывается основная функция, и в котором могут быть инициализированы переменные продолжительности хранения stati c (6.6.2) и destroy (6.6.4).

Но C ++ инициализация переменных stati c не так проста :-(. Этот же черновик написан позже в [basi c .start.dynamic] §4 (выделите мое):

Определяется реализацией, выполняется ли динамическая c инициализация нелокальной не встроенной переменной со статической длительностью хранения до первого оператора main или откладывается Если оно откладывается, это сильно случается до того, как любое неинициализирующее использование odr любой не встроенной функции или не встроенной переменной, определенной в той же единице перевода, что и переменная для инициализации. * 10 10 * Это определяется реализацией, в каких потоках и в каких точках программы происходит такая отложенная динамическая инициализация c .

Я считаю, что стандарт делает все возможное, чтобы предотвратить Программист делает предположения о моменте инициализации переменной * * * * * * * * *. Если реализация удобна для программиста, она инициализирует все нелокальные переменные stati c перед main в одном потоке - стандарт это позволяет. Но, к сожалению, это было бы непереносимо, потому что стандарт не предписывает это.

TL / DR: если вы нацелены на одну единственную реализацию, которая гарантирует инициализацию нелокальных переменных stati c перед вызовом main, тогда вы можете быть уверен, что эта инициализация будет происходить в одном потоке. Если вы храбры, вы можете попытаться понять, что означает , что это сильно случается перед любым не-инициализирующим использованием odr любой не встроенной функции или не встроенной переменной, определенной в той же единице перевода, что и переменная для инициализации и как ты мог это использовать. И если вам нужен только переносимый и надежный код, примите тот факт, что драконы скрыты вблизи инициализации stati c и что это может произойти в любом потоке ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...