2013-08-30 4 views
2

У меня есть коллекция, которую я защищаю с помощью мьютекса. После инициализации он только читается, поэтому мне не нужен мьютекс.Глобальная статическая инициализация threading

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


У меня есть статическая коллекция, защищенная счетчиком Шварца и заполняемая конструкторами других статических объектов. Контейнер связан с мьютексом. Учитывая, что коллекция доступна только для чтения после запуска main, я хотел бы избавиться от мьютекса, если я могу гарантировать, что статические конструкторы вызываются в одном потоке.

Мое понимание состоит в том, что статический порядок инициализации обычно хорошо определен в пределах одной единицы перевода, но не определен между единицами перевода. Позволяет ли стандарту инициализировать/создавать статические объекты с помощью разных потоков времени выполнения?


Schwarz счетчик:

Заголовок файла:

struct Init 
{ 
    Init(); 
    ~Init(); 
}; 
namespace 
{ 
    Init _init; 
} 
extern std::map<int, std::unique_ptr<...>> &protected; 

Исходный файл:

namespace 
{ 
    int init_count; 
    std::aligned_storage<sizeof(std::map<int, std::unique_ptr<...>>), alignof(std::map<int, std::unique_ptr<...>>>)> protected_storage; 
} 
std::map<int, std::uniqe_ptr<...>> &protected = *reinterpret_cast<std::map<int, std::unique_ptr<...>> *>(&protected_storage); 
Init::Init() 
{ 
    if (!init_counter++) 
    { 
     new(&protected_storage) std::map<int, std::unique_ptr<...>>(); 
    } 
} 
Init::~Init() 
{ 
    if (!--init_counter) 
    { 
     protected.~std::map<int, std::unique_ptr<...>>(); 
    } 
} 

Коллекция населения:

struct helper 
{ 
    helper(...) 
    { 
     protected.insert(std::make_pair(...)); 
    } 
}; 

Макрос разворачивается, что создает статические экземпляры помощника.

+1

В C++ 11 статическая инициализация не вводит гонку данных. –

+0

Статическая инициализация - либо инициализация нуля, либо * постоянная инициализация *. Я не думаю, что у вас могут быть наблюдаемые различия между многопоточными и однопоточными * static * init (нелокальных переменных). – dyp

+0

Действительно ли мы говорим о глобальных статических инициализаторах, или мы также рассматриваем конструкторы статических объектов? – jxh

ответ

3

Есть ли какая-либо гарантия, что глобальная статическая инициализация будет однопоточной?

Вы имеете в виду динамическую инициализацию. Нет, однопоточная инициализация явно не гарантируется.

От 3.6.2:

Если программа запускает поток (30,3), последующая инициализация из переменной unsequenced по отношению к инициализации переменной, определенной в другой перевод единицы. В противном случае инициализация переменной неопределенно секвенируется относительно инициализации переменной, определенной в другой единицы перевода. Если программа запускает поток, последующая неупорядоченная инициализация переменной не зависит от каждой другой динамической инициализации. В противном случае, неупорядоченный инициализация переменной неопределенно секвенировали по отношению к любой другой динамической инициализации

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

Лучший способ справиться с этими проблемами, чтобы обернуть ваши статические переменные длительности хранения как локальные статическими переменными в следующем «одноплодном шаблоне»:

const T& f() 
{ 
    static T t(a,b,c); 
    return t; 
} 

Последнего стандарт гарантирует, что строительство t является поточно -safe, поэтому вам вообще не нужен мьютекс (по крайней мере, не указано явно, компилятор будет генерировать для вас охранник).

В качестве дополнительного преимущества объект создается «лениво» при первом вызове f, поэтому вам не нужно беспокоиться о порядке инициализации. Если несколько таких синглонов называют друг друга в своих конструкторах (при условии, что зависимости ацикличны, конечно), они будут инициализированы в рабочем порядке. Это касается нелокальных переменных.

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