Какой-нибудь правильный способ достигнуть замков в ситуации как это? - PullRequest
0 голосов
/ 14 мая 2018

У меня есть массив объектов, с которыми я хочу работать в потоках, но я также хочу иметь доступ к ним время от времени.Это похоже на хакерский способ достижения моей цели, но есть ли лучший способ сделать что-то подобное?:
* основная цель - иметь 2 замка.Один, который позволяет всем отдельным потокам работать одновременно, блокируя доступ из массива до тех пор, пока все они не будут завершены, и другой, который позволяет закрыть доступ из потока, чтобы гарантировать, что никакие объекты не будут затронуты другими потоками во время выполнения функции.

atomic<int> inThreadCount;
atomic<int> arrayLock;
map<string, MyObj*> myMap;
mutex mu1;
class MyObj{
    mutex mu2;
    int myInt;
    public: 
    void update(bool shouldLowerCount){
        mu2.lock();
        myInt++;
        if (shouldLowerCount)
            inThreadCount--;
        mu2.unlock();
    }
}
//Some operation that requires all threads to finish first
//and doesn't allow threads to access the objects while running
void GetSnapshot(){ 
    mu1.lock();
    arrayLock++;
    while (inThreadCount > 0)
        Sleep(0);
    map<string, MyObj *>::iterator it = myMap.begin();
    auto t = time(nullptr);
    auto tm = *localtime(&t);
    cout << put_time(&tm, "%d-%m-%Y %H-%M-%S") << endl;
    for( ; it != myMap.end(); ++it){
        cout << it->first << ":" << it->second->counter);
    }
    arrayLock--;
    mu1.unlock();
}

void updateObject(MyObj* myObj){
    while (arrayLock > 0)
        Sleep(0);
    inThreadCount++;
    async(std::launch::async, myObj->update(true));
}

PS, я понимаю, что есть небольшое окно для ошибки между Sleep () и arrayLock / inThreadCount ++.Это часть проблемы, которую я хочу решить!

1 Ответ

0 голосов
/ 14 мая 2018

Я думаю, вы просите общий мьютекс.Общий мьютекс (или мьютекс чтения-записи) позволяет многим потокам параллельно блокировать объект, одновременно позволяя одному потоку одновременно блокировать его исключительно.

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

Обычно используется эксклюзивность чтения и записи.Смотрите общий доступ для чтения и эксклюзивный доступ для записи.Это верно, потому что гонка данных может происходить только тогда, когда два или более потоков обращаются к одним и тем же данным, и по крайней мере один из них является операцией записи.Множество считывателей - это не гонка данных.

Обычно при реализации общей блокировки возникают издержки, а не монопольная блокировка, и модель обычно помогает только тогда, когда есть «много» читателей, которые «читают» часто и пишутоперации «редки».Что означает «многие», «частые» и «нечастые», зависит от платформы и проблемы в руках.

Это именно то, для чего предназначен общий мьютекс.C ++ 17 поддерживает это из коробки с помощью std::shared_mutex, но я заметил, что вопрос помечен C ++ 11.

Некоторые реализации предлагали это в течение некоторого времени (это классическая стратегия блокировки) Или вы можетеtry boost::shared_mutex<>.

NB. Одна из проблем в общей блокировке состоит в том, чтобы избежать live-lock на устройстве записи.Если есть много читателей, которые часто читают, то может быть легко, чтобы писатель был «заблокирован» на неопределенный срок и никогда не прогрессировал (или прогрессировал очень медленно).Хорошая общая блокировка обеспечит некоторую гарантию того, что автор в конечном итоге получит свою очередь.Это может быть абсолютным приоритетом (авторам не разрешается запускаться после того, как поток начинает ждать

...