2015-01-27 2 views
0

У меня есть класс «config», в котором есть куча атрибутов, которые «зеркалируют» настройки конфигурации. Один экземпляр класса делится по всему коду (используя объекты boost shared_ptr) и его атрибуты, считываемые несколькими потоками (около 100).Лучший способ контролировать доступ к строковому объекту в многопоточной программе

Иногда настройки могут меняться, а поток «монитора» обновляет соответствующие атрибуты в объекте.

Для атрибутов integer и bool я использую boost atom, так что, когда происходит обновление, и поток монитора устанавливает значение, ни один из прочитанных потоков не читает его в частично обновленном состоянии.

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

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

Так, чтобы дать пример:

class Config 
{ 
    public: 
    boost::atomic<boost::shared_ptr<std::string> > configStr1; 

    void updateValueInMonitorThread(std::string newValue) 
    { 
     boost::shared_ptr<string> newValuePtr; 
     newValuePtr = newValue; 
     configStr1 = newValuePtr; 
    } 
}; 

void threadThatReadsConfig(boost::shared_ptr<Config> theConfig) 
{ 
    std::map<std::string, std::string> thingImWorkingOn; 
    thingImWorkingOn[*(theConfig->configStr1.load())] = "some value"; 
} 

является то, что массовое убийство? Есть ли лучший способ сделать это? Мне действительно не нравится, как поток чтения должен получить доступ к значению, разыменовывая его и вызывая .load(). Кроме того, он даже потокобезопасен, или же этот материал фактически отрицает функции безопасности атомарного и/или shared_ptr-типа?

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

Заранее благодарим за любые предложения/информацию!

ответ

1

Вы уже даете каждому потребителю shared_ptr для объекта конфигурации. Поэтому потоки не заметят, если объект конфигурации не всегда является одним и тем же объектом.

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

Очевидно, это изменяет семантику использования объекта конфигурации. Долгосрочный поток, который хотел бы заметить изменения конфигурации, должен будет периодически обновлять свой объект конфигурации. Самый простой способ сделать это - просто получить новый объект конфигурации при каждом использовании данных конфигурации; опять же, это вряд ли будет слишком дорого, если вы не используете строку конфигурации в жестком цикле.

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

0

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