2015-11-24 96 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