c ++中线程安全索引操作符的正确方法

时间:2015-02-26 19:44:10

标签: c++ multithreading indexing thread-safety

我想拥有线程安全的索引操作符,并且我附带了以下代码,它似乎有效。 除了边界检查之外,你能看到它的任何问题吗? 有没有更好的方法来做同样的事情(使用重载索引操作符,而不是get / set函数)?

class A
{
public:

A()
{
    for (auto i = 0; i < 100; ++i)
    {
        v[i] = i + 1;
    }
};


    class Proxy
    {
        int* val;
        A* parent;
    public:
        Proxy(int& a, A* p) : parent(p) 
        {
            parent->z.lock();
            val = &a;
        };

        ~Proxy()
        {
            parent->z.unlock();
        }

        int operator=(int a) 
        {
            *val = a;
            return a;
        };

        operator int() const
        {
            return *val;
        };
    };


int operator[](int i) const
{
    z.lock();
    int r = v[i];
    z.unlock();
    return r;
}


Proxy operator[](int i)
{
    return Proxy(v[i], this);
}


int v[100];
Z z; // some locking mechanism, not important

};

1 个答案:

答案 0 :(得分:0)

由于未指定锁定机制,我认为它使用普通的互斥锁,在这种情况下,明显的问题是:

A a;
a[0] = a[1];

换句话说,很容易死锁程序。使用递归互斥锁可以避免这个问题。

另一个明显的问题是代码依赖于copy-elision,而不能保证永远不会发生。如果在返回时没有删除副本,则临时将释放锁,并且副本将再次释放它,这通常是未定义的行为。此外,访问该成员是无人看守的,并可能引入数据竞赛。要避免此问题,您应该定义一个移动构造函数,并确保移动的状态不会尝试释放互斥锁,例如:

A::Proxy::Proxy(Proxy&& other)
    : val(other.val)
    , parent(other.parent) {
    other.parent = 0;
}
A::Proxy::~Proxy() {
    if (parent){
        parent->unlock();
    }
}

不那么明显的问题是它不太可能导致有效的实施。