在这种情况下有什么正确的方法来实现锁定?

Any proper way to achieve locks in a situation like this?

我有一个对象数组,我想在线程中对其进行操作,但我也希望有时能够访问。这感觉像是实现我的目标的一种 hacky 方法,但是有没有更好的方法来做这样的事情?:
*基本目标是拥有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++ 之间存在微小的 window 错误机会。这就是我要解决的部分问题!

我认为您要求的是共享互斥锁。 共享互斥锁(或读写互斥锁)允许多个线程并行锁定一个对象,同时还允许一次一个线程独占锁定它。

简单来说,如果一个线程请求共享访问,它就会被授予,除非一个线程独占地持有该对象。当对象未被任何其他线程持有(共享或独占)时,线程被授予独占性。

它的常见用途是读写排他性。请参阅读取的共享访问权限和写入的独占访问权限。这是有效的,因为只有当两个或多个线程访问相同数据并且其中至少一个是写操作时,才会发生数据竞争。多个读者不是数据竞赛。

与独占锁相比,实现共享锁通常会产生开销,并且该模型通常只在有 'many' 读者的情况下有帮助 读取 'frequently' 和写入操作是 'infrequent'。 'many'、'frequent' 和 'infrequent' 的含义取决于平台和手头的问题。

这正是共享互斥锁的用途。 C++17 支持开箱即用 std::shared_mutex 但我注意到这个问题被标记为 C++11.

有些实现已经提供了一段时间(这是一种经典的锁定策略) 或者你可以试试 boost::shared_mutex<>.

注意:共享锁的挑战之一是避免对写入器进行活锁。 如果有很多读者经常阅读,那么作者很容易无限期地获得 'locked out' 并且永远不会进步(或进步非常缓慢)。 一个好的共享锁将为作者最终获得轮到提供一些保证。这可能是绝对优先级(不允许编写器在线程开始等待后启动