Есть ли способ провести арбитраж между двумя различными источниками обновлений без блокировки?

Я получаю обновления из двух разных источников (прослушивание сети), по которым я получаю обратный вызов метода, похожего на этот:

void onUpdate(Update* update)
{
static MutexT lock;
static hash_set<UpdateID> set;

ScopedGuard _(lock); //lock here
hash_set<UpdateID>::iterator it = set.find(update->id);
if (it == set.end())
set.insert(update->id);
else
return;

listener->onUpdate(/*some stuff*/);
}

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

(Или хотя бы способ снизить стоимость?)

2

Решение

Прежде всего, блокировка не должна быть статической, она должна быть переменной-членом.

Вы можете сделать это более эффективным, используя мьютекс читателя / писателя, например,

boost::shared_mutex          mutex_;
std::unordered_set<UpdateID> set_;

void onUpdate(const Update& update)
{
boost::upgrade_lock<boost::shared_mutex> lock(mutex_);

auto it = set_.find(update.id);
if(it == set_.end())
{
boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(mutex_);
set.insert(update.id);
}

listener->onUpdate(/*some stuff*/);
}
2

Другие решения

То есть вы просто постоянно добавляете записи в свою хэш-таблицу? Никогда не удаляя их? Как выглядит загрузка вашей хеш-таблицы? При достаточном количестве столкновений ваша производительность вставки / поиска будет ухудшаться.

Если в вашем потоке есть порядковые номера, я думаю, вам лучше отслеживать пропуски (пропущенные порядковые номера) вместо сообщений, которые вы на самом деле видели. На стороне быстрого UDP, когда порядковые номера имеют пробелы, запишите пропущенные сообщения в хеш-таблицу и вызывайте onUpdate () для каждого полученного сообщения. На медленной стороне TCP, посмотрите в хеш-таблице, чтобы увидеть, заполняет ли сообщение пробел, если он вызывает onUpdate () и удаляет это сообщение из хеш-таблицы, иначе ничего не делает.

Тем не менее, хэш-таблица без блокировки возможна. Не уверен, что они без блокировки, но у Microsoft есть concurrent_unordered_map (а также concurrent_unordered_set) и TBB имеет concurrent_hash_map.

0

Здесь шаблон проверки двойной блокировки где вы избегаете дорогостоящей блокировки, проверяя состояние вставки два раза. Но что дороже: запирание или нахождение.

-1
По вопросам рекламы [email protected]