У меня есть система кеширования в одной из моих программ. У меня есть один статический класс, который поддерживает этот кеш и одновременно использует кеш в нескольких потоках. Я столкнулся с проблемой правильной работы системы кэширования. Вот пример кода.Как правильно перемещать/читать из shared_ptr
class db_cache
{
public:
typdef std::map<int, int> map_t;
static void update_cache();
static boost::shared_ptr< const map_t > get_cache();
private:
db_cache();
static void run_update();
static boost::shared_ptr< const map_t > cur_cache_;
static boost::shared_ptr< const map_t > old_cache_;
};
void db_cache::update_cache()
{
cur_cache_ = boost::make_shared<map_t>();
old_cache_ = boost::make_sahred<map_t>();
//
//Setup connection to server that sends updates
//
//Initialize cache
run_update();
while(true)
{
if(recv().compare("update") == 0)
{
//Update cache if update message recieved
run_update();
}
}
}
void db_cache::run_update()
{
//Create new cache to swap with current cache
auto new_cache = boost:make_shared<map_t>();
//
//Put data in new cache
//
boost::atomic_store(&old_cache_, boost::move(cur_cache_));
boost::atomic_store(&cur_cache_, boost::shared_ptr< const map_t >(boost::move(new_cache)));
}
auto db_cache::get_cache() -> boost::shared_ptr< const map_t >
{
return boost::atomic_load(&cur_cache_);
}
В настоящее время я получаю аварии на boost::atomic_store(&old_cache_, boost::move(cur_cache_));
. Сбой, по-видимому, связан с тем, что old_cache_
- null. Это происходит во второй раз, когда получено сообщение об обновлении. Я предполагаю, что происходит (не 100% уверен, но только один способ, которым я могу думать), это:
- Первый раз сообщение получено,
cur_cache_
копируется вold_cache_
. cur_cache_
заменен наnew_cache
, в результате чего старыйcur_cache_
(что в настоящее время указываетсяold_cache_
), чтобы быть пустым.old_cache_
вызывает сбои, когдаboost::atomic_store
вызывается снова из-за его нулевого значения.
Мой вопрос, почему boost::atomic_store(&old_cache_, boost::move(cur_cache_));
не вызывает опорный счетчик cur_cache_
для увеличения. Есть ли способ сделать это возможным?
Другое примечание:
Причина у меня есть old_cache_
, потому что я считаю, у меня была проблема при чтении из кэша, который, скорее всего, также является проблемой. Моя программа, казалось, терпела крах при попытке прочитать элементы с карты, возвращенной с get_cache()
, поэтому, чтобы убедиться, что они остались в области действия до тех пор, пока не будут выполнены все потоки, которые в настоящее время имеют копию, я сохраняю последнюю версию кеша. Я полагаю, что если бы у меня был правильный способ сделать это, я мог бы полностью избавиться от old_cache_
, что должно решить проблему выше.
Edit:
Вот код, использующий кэш-памяти:
//Vector big, don't want to copy
const std::vector *selected_vec = &(*db_cache::get_cache()).at(get_string);
for(std::vector<std::string>::iterator it = selected_vec->begin(), e = selected_vec->end(); it != e; ++it)
{
//String can be big, don't want to copy
const std::string *cur_string = &(*it);
if(cur_string == nullptr || cur_string->size() == 0)
{
continue;
}
char a = cur_string->at(0); //Crash here
//Do Stuff
}
Мой фактический map_t
тип является std::map<std::string,std::vector<std::string>>
типа не std::map<int,int>
. После звонка get_cache()
, я получаю вектор, который я хочу, и итератор над вектором. Для каждой строки я пытаюсь получить первый символ. Когда я пытаюсь получить char, программа выйдет из строя. Единственное, о чем я могу думать, это то, что selected_vec
удален.
замечательные, спасибо за 'atomic_exchange' функции , Что касается второй части, это было изначально то, что у меня было, но у меня возникла проблема. Я обновляю исходное сообщение с помощью некоторого примерного кода того, что делает моя программа. Думаю, мой вопрос в том, есть ли какая-то причина, по которой вы можете думать, что кеш будет удален до того, как мои потоки с помощью 'cur_cache' будут закончены. Должна ли моя функция get_cache() 'не увеличивать значение use_count для' shared_ptr' каждый раз, когда вызывается 'get_cache()'? – Eumcoz
@Eumcoz 'get_cache' возвращает копию' shared_ptr', которая * * увеличивает свой 'use_count'. Проблема в клиентском коде заключается в том, что она удаляет эту копию 'shared_ptr' - уменьшает значение' use_count' - * before *, обращаясь к внутренним объектам, на которые указывал 'shared_ptr'. – Casey
Удивительно, спасибо вам за помощь, имеет смысл! – Eumcoz