在这种情况下实现锁定的任何正确方法?

时间:2018-05-14 08:48:15

标签: c++ multithreading c++11 mutex

我有一个对象数组,我想在线程中操作,但我也希望有时能够访问。这对于实现我的目标感觉就像一种愚蠢的方式,但是有更好的方法来做这样的事情吗? *基本目标是拥有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 :(得分:4)

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

简单来说,如果一个线程请求共享访问,那么除非一个线程专门持有该对象,否则它被授予。当对象未被任何其他线程保持(共享或排他)时,线程被授予排他性。

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

实现共享锁通常会产生开销,而不是排他锁,而且模型通常只会帮助“有很多”读者  读“经常”和写操作是“不常见”。 “很多”,“频繁”和“不常见”意味着取决于平台和手头的问题。

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

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

注意:共享锁中的一个挑战是避免写入程序的实时锁定。 如果有许多读者经常阅读,那么作者可以很容易地无限期地“锁定”并且永远不会进展(或者进展非常缓慢)。 一个好的共享锁将为作者最终获得转机提供一些保证。这可能是绝对的优先级(在线程开始循环后不允许编写者启动