Нормально ли для статической инициализации C ++ дважды появляться в одной и той же трассировке? - PullRequest
4 голосов
/ 15 апреля 2010

Я пытаюсь отладить программу на C ++, скомпилированную с GCC, которая зависает при запуске. Мьютекс GCC защищает статические локальные переменные функции, и кажется, что ожидание получения такой блокировки - вот почему она зависает. Как это происходит, довольно запутанно. Происходит статическая инициализация первого модуля A (есть функции __static_init, которые GCC вызывает, которые видны в обратном следе), которая вызывает функцию Foo (), которая имеет статическую локальную переменную. Статическая локальная переменная - это объект, который конструктор вызывает через несколько слоев функций, затем внезапно обратная трассировка имеет несколько символов, а затем происходит статическая инициализация второго модуля B (функции __static возникают снова и снова) , который затем вызывает Foo (), но так как Foo () никогда не возвращал первый раз, когда мьютекс локальной статической переменной все еще установлен, и он блокируется.

Как один статический инициатор может вызвать другой? Моей первой теорией были разделяемые библиотеки - этот модуль A будет вызывать некоторую функцию в модуле B, которая вызовет загрузку модуля B, вызывая статический init B, но это не так. Модуль A вообще не использует модуль B. Итак, у меня есть второе (и ужасающее) предположение. Скажи это:

  1. Модуль A использует некоторую шаблонную функцию или функцию в шаблонном классе, например, foo<int>::bar()

  2. Модуль B также использует foo<int>::bar()

  3. Модуль A вообще не зависит от модуля B

  4. Во время компоновки у компоновщика есть два экземпляра foo<int>::bar(), но это нормально, потому что функции шаблона помечены как слабые символы ...

  5. Во время выполнения модуль A вызывает foo<int>::bar, и запускается статическая инициализация модуля B, даже если модуль B не зависит от модуля A! Зачем? Потому что компоновщик решил использовать экземпляр b модуля foo :: bar вместо экземпляра модуля A во время компоновки.

Допустим ли этот конкретный сценарий? Или статический init одного модуля никогда не должен запускать статический init в другом модуле?

Пояснение: GCC автоматически создает мьютексы для защиты любой статической переменной функции. Я ничего не делаю с мьютексами сам. Это способ, используемый GCC для обеспечения безопасности потоков статических переменных функций.

Обновление : я знаю, что статическая инициализация не определена между единицами перевода и что я не должен зависеть от заказа. Но мне любопытно, если это нормальное поведение как ключ к устранению проблемы. Это нормально для компилятора генерировать код, который делает это, или это потенциально указывает на ошибку в GCC?

Ответы [ 2 ]

4 голосов
/ 15 апреля 2010

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

2 голосов
/ 15 апреля 2010

Билл вытаскивает Эффективный предмет C ++ 4 :

порядок инициализации нелокальных статических объектов, определенных в разных единицах перевода, не определен

Проще говоря, компилятору разрешено делать все, что он хочет.

...