2015-11-24 56 views
4

假设我有以下的过于简单化的类,并且要防止从多线程访问的资源。我如何可以将某事像一类的锁,其中每个“入口点”进入公共接口首先必须获得被允许使用的界面之前一类锁?如何实现类锁定对象的多线程访问

class MyClass 
{ 
    public: 
    void A(); 
    void B(); 
    void C(); 
    void D(); 
    void E(); 

    private: 
    SharedResource _res; 
} 

void MyClass::A() 
{ 
    B(); 
    C(); 
    D(); 
    E(); 
} 

void MyClass::B() 
{ 
    // do sth with _res 
} 

void MyClass::C() 
{ 
    // do sth with _res 
} 

void MyClass::D() 
{ 
    // do sth with _res 
} 

void MyClass::E() 
{ 
    // do sth with _res 
} 

我可以在每个方法锁定一类互斥做到这一点,然后有方法的两个版本,像这样:

void MyClass::A() 
{ 
    std::lock<std::mutex> lock(_mutex); 
    B_mtx(); 
    C_mtx(); 
    D_mtx(); 
    E_mtx(); 
} 

void MyClass::B() 
{ 
    std::lock<std::mutex> lock(_mutex); 
    B_mtx(); 
} 

void MyClass::B_mtx() 
{ 
    // logic of B 
} 

// ... 

但是,这实际上看起来更繁琐,很难得到正确的除要求客户先问类的锁定对象,然后较大,较复杂的接口被允许,直到他再次释放锁savely使用类的接口。 有没有一种方法可以轻松实现?我只是有一个方法GETLOCK,我在一类互斥和使用布展分配新建分配FY创建一个锁得到它的客户端?我怎样才能确保调用者在调用方法时拥有锁?

+0

好吧,你目前的代码是万无一失简单的解决方案[该类管理它自己的threadsafety] ...是的,它可以是麻烦。通过仅包含原始类的锁和实例的包装类,至少子方法调用不再是问题。 – deviantfan

回答

2

如果需要类是线程安全的,也就是说,只有一个锁下使用,可以使所有的公共职能接受一个std::lock(最好是包裹在一个自定义对象的引用,或至少一个typedef):

class MyClass 
{ 
    mutable std::mutex mtx; 

public: 
    using Lock = std::unique_lock<std::mutex>; 

    void A(Lock &l) 
    { 
    assert(l.mutex() == mtx); 
    // ... 
    } 

    void B(Lock &l) 
    { 
    assert(l.mutex() == mtx); 
    // ... 
    } 

    Lock getLock() const 
    { return Lock(mtx); } 

    void releaseLock(Lock &&l) const 
    { Lock l2 = std::move(l); } 
}; 

然而,另一种是让该类忽略锁定问题,而是为它提供一个线程安全的包装。一个非常类似的想法在他的会谈(1)之一呈现由香草萨特:

class MyClass 
{ 
public: 
    void A() 
    { 
    //... 
    } 

    void B() 
    { 
    //... 
    } 
}; 

class MyClass_ThreadSafe 
{ 
    MyClass m; 
    std::mutex mtx; 

public: 
    template <class Operation> 
    auto call(Operation o) -> decltype(o(m)) 
    { 
    std::unique_lock l(mtx); 
    return o(m); 
    } 
}; 

// Usage: 

MyClass_ThreadSafe mc; 
mc.call(
    [](MyClass &c) 
    { 
    c.A(); 
    c.B(); 
    } 
); 

(1)C++ and Beyond 2012 — Herb Sutter: C++ Concurrency从分36。

+0

伟大的解决方案! – user1709708