这是使用C++锁定容器的可接受方法吗?

mat*_*975 6 c++ oop multithreading thread-safety

我需要以这样一种方式实现(在C++中)线程安全容器,只有一个线程能够从容器中添加或删除项目.我之前通过在线程之间共享互斥锁来完成此类操作.这会导致很多互斥对象在我的代码中被乱丢,并且使得事情变得非常混乱并且难以维护.

我想知道是否有更整洁,更面向对象的方式来做到这一点.我想到了容器周围的以下简单类包装器(半伪C++代码)

 class LockedList {
    private:
        std::list<MyClass> m_List;

    public:
        MutexObject Mutex;
 };
Run Code Online (Sandbox Code Playgroud)

这样可以通过以下方式完成锁定

 LockedList lockableList;     //create instance
 lockableList.Mutex.Lock();    // Lock object

 ... // search and add or remove items

 lockableList.Mutex.Unlock();   // Unlock object
Run Code Online (Sandbox Code Playgroud)

所以我的问题是从设计的角度来看这是否是一个好的方法?我知道从设计的角度来看,允许公众访问成员是不受欢迎的,上述设计是否存在任何严重缺陷.如果是这样,有更好的方法来实现线程安全的容器对象?

我已经阅读了很多关于设计和C++的书籍,但似乎确实存在关于多线程编程和多线程软件设计的文献缺失.

如果以上是解决问题的一种不好的方法,我可以有人建议一种方法来改进它,或者指出一些信息,解释设计类是线程安全的好方法??? 非常感谢.

Dir*_*ple 7

我会做这样的事情,通过使用RAII使其更加异常安全.

class LockedList {
private:
    std::list<MyClass> m_List;
    MutexObject Mutex;
    friend class LockableListLock;
};

class LockableListLock {
private:
    LockedList& list_;
public:
    LockableListLock(LockedList& list) : list_(list) { list.Mutex.Lock(); }
    ~LockableListLock(){ list.Mutex.Unlock(); }
}
Run Code Online (Sandbox Code Playgroud)

你会像这样使用它

LockableList list;
{
    LockableListLock lock(list); // The list is now locked.

    // do stuff to the list

} // The list is automatically unlocked when lock goes out of scope.
Run Code Online (Sandbox Code Playgroud)

您还可以通过在LockableListLock中为std :: list的接口添加包装来强制您在执行任何操作之前锁定它,因此您不必通过LockedList类访问列表,而是通过LockableListLock类访问列表.例如,你可以围绕std :: list :: begin()创建这个包装器

std::list::iterator LockableListLock::begin() {
    return list_.m_List.begin();
}
Run Code Online (Sandbox Code Playgroud)

然后像这样使用它

LockableList list;
LockableListLock lock(list);
// list.begin();   //This is a compiler error so you can't 
                   //access the list without locking it
lock.begin(); // This gets you the beginning of the list
Run Code Online (Sandbox Code Playgroud)

  • 不必为每个要使用的方法做一个包装,而是可以通过LockableListLock中的`operator-&gt;()`公开列表。这使用户可以在其上调用方法,但从不获取用于存储的引用或指针。`std :: list &lt;MyClass&gt; * LockableListLock :: operator-&gt;(){返回&list_.m_List;}` (2认同)

Mar*_*ork 7

我宁愿设计一个resourece所有者来锁定互斥锁并返回一个可供线程使用的对象.一旦线程完成它并停止使用该对象,资源就会automatically返回给它的所有者并释放锁.

template<typename Resource>
class ResourceOwner
{
      Lock         lock; 
      Resource     resource;

      public:
         ResourceHolder<Resource>  getExclusiveAccess()
         {
              // Let the ResourceHolder lock and unlock the lock
              // So while a thread holds a copy of this object only it
              // can access the resource. Once the thread releases all
              // copies then the lock is released allowing another
              // thread to call getExclusiveAccess().
              //
              // Make it behave like a form of smart pointer
              //    1) So you can pass it around.
              //    2) So all properties of the resource are provided via ->
              //    3) So the lock is automatically released when the thread
              //       releases the object.

              return ResourceHolder<Resource>(lock, resource);
         }
};
Run Code Online (Sandbox Code Playgroud)

资源持有者(没想到这样可以改进)

template<typename Resource>
class ResourceHolder<
{
    // Use a shared_ptr to hold the scopped lock
    // When first created will lock the lock. When the shared_ptr
    // destroyes the scopped lock (after all copies are gone)
    // this will unlock the lock thus allowding other to use
    // getExclusiveAccess() on the owner
    std::shared_ptr<scopped_lock>    locker;
    Resource&                        resource;   // local reference on the resource.

    public:
        ResourceHolder(Lock& lock, Resource& r)
            : locker(new scopped_lock(lock))
            , resource(r)
        {}

        // Access to the resource via the -> operator
        // Thus allowing you to use all normal functionality of 
        // the resource.
        Resource* operator->() {return &resource;}
};
Run Code Online (Sandbox Code Playgroud)

现在一个可锁定的列表是:

ResourceOwner<list<int>>  lockedList;

void threadedCode()
{
    ResourceHolder<list<int>>  list = lockedList.getExclusiveAccess();

    list->push_back(1);
}
// When list goes out of scope here. 
// It is destroyed and the the member locker will unlock `lock`
// in its destructor thus allowing the next thread to call getExclusiveAccess()
Run Code Online (Sandbox Code Playgroud)