繁体   English   中英

线程安全的无锁阵列

[英]Thread-safe lock-free array

我有一个C ++库,它应该在多个线程上进行一些计算。 我创建了独立的线程代码(即它们之间没有共享变量),除了一个数组。 问题是,我不知道如何使其成为线程安全的。

我看了互斥锁/解锁( QMutex ,因为我正在使用Qt),但它不适合我的任务 - 一个线程将锁定互斥锁,其他线程将等待!

然后我读到了std::atomic ,它看起来就像我需要的那样。 不过,我尝试以下列方式使用它:

std::vector<std::atomic<uint64_t>> *myVector;

并且它产生了编译器错误( 使用已删除的函数'std :: atomic :: atomic(const std :: atomic&)' )。 然后我找到了解决方案 - 为std::atomic使用特殊包装器。 我试过这个:

struct AtomicUInt64
{
    std::atomic<uint64_t> atomic;

    AtomicUInt64() : atomic() {}

    AtomicUInt64 ( std::atomic<uint64_t> a ) : atomic ( atomic.load() ) {}

    AtomicUInt64 ( AtomicUInt64 &auint64 ) : atomic ( auint64.atomic.load() ) {}

    AtomicUInt64 &operator= ( AtomicUInt64 &auint64 )
    {
                atomic.store ( auint64.atomic.load() );
    }
};

std::vector<AtomicUInt64> *myVector;

这个东西成功编译,但是当我无法填充向量时:

myVector = new std::vector<AtomicUInt64>();

for ( int x = 0; x < 100; ++x )
{
    /* This approach produces compiler error:
     * use of deleted function 'std::atomic<long long unsigned int>::atomic(const std::atomic<long long unsigned int>&)'
     */
    AtomicUInt64 value( std::atomic<uint64_t>( 0 ) ) ;
    myVector->push_back ( value );

    /* And this one produces the same error: */
    std::atomic<uint64_t> value1 ( 0 );
    myVector->push_back ( value1 );
}

我究竟做错了什么? 我假设我尝试了一切(也许不是,但无论如何)并没有任何帮助。 在C ++中有没有其他方法可以进行线程安全的数组共享?

顺便说一下,我在Windows上使用MinGW 32bit 4.7编译器。

以下是AtomicUInt64类型的清理版本:

template<typename T>
struct MobileAtomic
{
  std::atomic<T> atomic;

  MobileAtomic() : atomic(T()) {}

  explicit MobileAtomic ( T const& v ) : atomic ( v ) {}
  explicit MobileAtomic ( std::atomic<T> const& a ) : atomic ( a.load() ) {}

  MobileAtomic ( MobileAtomic const&other ) : atomic( other.atomic.load() ) {}

  MobileAtomic& operator=( MobileAtomic const &other )
  {
    atomic.store( other.atomic.load() );
    return *this;
  }
};

typedef MobileAtomic<uint64_t> AtomicUInt64;

并使用:

AtomicUInt64 value;
myVector->push_back ( value );

要么:

AtomicUInt64 value(x);
myVector->push_back ( value );

你的问题是你拿了一个std::atomic的值,这会导致一个被阻止的副本。 哦,你没能从operator=返回。 我也做了一些明确的构造函数,可能是不必要的。 我将const添加到你的拷贝构造函数中。

我也很想将storeload方法添加到MobileAtomic ,然后转发到atomic.storeatomic.load

您正在尝试复制不可复制的类型: AtomicUInt64构造函数按值获取atomic

如果你需要它可以从atomic初始化,那么它应该采用(const)引用的参数。 但是,在您的情况下,看起来您根本不需要从atomic初始化; 为什么不从uint64_t初始化呢?

还有几个小问题:

  • 复制构造函数和赋值运算符应该通过const引用获取它们的值,以允许复制临时值。

  • new分配矢量是一件相当奇怪的事情; 你只是增加了额外的间接水平而没有任何好处。

  • 确保在其他线程可能正在访问它时,永远不会调整阵列大小。

这条线

AtomicUInt64 ( std::atomic<uint64_t> a ) : atomic ( atomic.load() ) {}

您完全忽略了传入的参数,您可能希望它是a.load(),并且您可能希望通过const引用获取元素,这样它们就不会被复制。

AtomicUInt64 (const std::atomic<uint64_t>& a) : atomic (a.load()) {}

至于你在做什么,我不确定它是否正确。 对数组内部变量的修改将是原子的,但是如果向量被修改或重新分配(可以使用push_back ),那么没有什么可以保证你的数组修改在线程之间工作并且是原子的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM