Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 引用计数线程安全吗_C++_Multithreading - Fatal编程技术网

C++ 引用计数线程安全吗

C++ 引用计数线程安全吗,c++,multithreading,C++,Multithreading,例如,考虑 class ProcessList { private std::vector<std::shared_ptr<SomeObject>> list; Mutex mutex; public: void Add(std::shared_ptr<SomeObject> o) { Locker locker(&mutex); // Start of critical section. Locker release

例如,考虑

class ProcessList {
private
   std::vector<std::shared_ptr<SomeObject>> list;
   Mutex mutex;
public:
   void Add(std::shared_ptr<SomeObject> o) { 
       Locker locker(&mutex); // Start of critical section. Locker release so will the mutex - In house stuff
       list.push_back(std::make_shared<SomeObject>(o).
   }

   void Remove(std::shared_ptr<SomeObject> o) { 
       Locker locker(&mutex); // Start of critical section. Locker release so will the mutex - In house stuff
       // Code to remove said object but indirectly modifying the reference count in copy below
   }

   void Process() {
       std::vector<std::shared_ptr<SomeObject>> copy;

       {
           Locker locker(&mutes);
           copy = std::vector<std::shared_ptr<SomeObject>>(
                list.begin(), list.end()
           )
       }
       for (auto it = copy.begin(), it != copy.end(); ++it) {
           it->Procss(); // This may take time/add/remove to the list
       }
    }
};
类进程列表{
私有的
std::向量表;
互斥互斥;
公众:
void Add(std::shared_ptr o){
锁柜(&mutex);//关键部分的开始。锁柜释放,互斥锁内部的东西也会释放
列表。向后推(标准::使共享(o)。
}
void Remove(std::shared_ptr o){
锁柜(&mutex);//关键部分的开始。锁柜释放,互斥锁内部的东西也会释放
//删除所述对象但间接修改以下副本中的引用计数的代码
}
无效过程(){
std::向量拷贝;
{
储物柜(和静音);
复制=标准::向量(
list.begin(),list.end()
)
}
对于(auto it=copy.begin(),it!=copy.end();+it){
it->Procss();//这可能需要时间/添加/删除到列表中
}
}
};
一个线程运行
进程
。多个线程运行添加/删除


是否引用计数是安全的和总是正确的?还是应该在它周围放置互斥体?

< p>除非CPU架构具有原子增量/递减,并且使用它作为引用计数,那么,不,它不安全;C++不保证对其任何标准类型的X++/X操作的线程安全性。

如果编译器支持(C++11),请使用
atomic
,否则需要使用锁

其他参考资料:


    • 使用互斥锁进行引用计数将是一种开销

      在内部,互斥体使用原子操作,基本上互斥体执行内部线程安全引用计数。因此,您可以直接使用原子进行引用计数,而不是使用互斥体,并且基本上做双倍的工作。

      是的,标准是(至少从N3997起,§20.8.2.2)这是为了要求引用计数是线程安全的

      对于您的简单案例,如添加:

      void Add(std::shared_ptr<SomeObject> o) { 
          Locker locker(&mutex);
          list.push_back(std::make_shared<SomeObject>(o).
      }
      
      这将以原子操作的形式执行整个复制--在复制过程中,任何其他操作都无法修改列表。这将确保您的副本为您提供列表的快照,与启动复制时的快照完全相同。如果您消除互斥,引用计数仍将工作,但您的副本可能会反映在复制过程中所做的更改g制造

      换句话说,
      shared_ptr
      的线程安全性只确保每个单独的增量或减量是原子的——它不能确保整个列表的操作是原子的,就像互斥锁在这种情况下所做的那样

      由于您的
      列表
      实际上是一个
      向量
      ,因此您应该能够将复制代码稍微简化为
      copy=list

      还请注意,您的
      Locker
      似乎是
      std::lock\u guard
      提供的一个子集。您似乎可以使用:

      std::lock_guard<std::mutex> locker(&mutes);
      
      std::锁护柜(&mutes);
      

      …在它的位置非常容易。

      引用计数可以线程安全地实现。考虑到C++11也有线程,我假设refcounting也是以线程安全的方式实现的。顺便说一句:甚至Boost的原始
      shared_ptr
      也已经是线程安全的。每个引用计数都有互斥锁吗?不,它们使用原子操作。您可以对每个计数器使用一个互斥锁来实现它们,但这将是低效的。您也可以使用一个全局互斥锁来实现它们,这将更简单,但效率可能仍然低于使用原子的效率。@UlrichEckhardt的标准指令是这样的(那
      shared_ptr
      是线程安全的)?如果是,你能提供一个参考吗?谢谢。第一个链接回答了这个问题。问题是
      std::shared_ptr
      (这是OP提供的代码中使用的)是否是线程安全的。这里没有“x++/x--”操作(除非它在共享_ptr实现中)。但是vector线程也是安全的吗?我认为两者之间不是这样的。无论如何,我们的locker在日志记录方面做了一些额外的工作。@EdHeal:没有什么可以禁止vector实现提供线程安全,但也不是必需的。如果多个线程修改vector,那么是的,您需要向我们报告e一个互斥锁(或任何东西)来序列化访问。它是共享指针的向量。-所以这些项是安全的,但向量不是-是吗correct@EdHeal:是的,这就是我的想法。
         {
             Locker locker(&mutes);
             copy = std::vector<std::shared_ptr<SomeObject>>(
                  list.begin(), list.end()
             )
         }
      
      std::lock_guard<std::mutex> locker(&mutes);