我真的很感谢有关此事的一些建议。

例如

class Foo
{
    TData data;
public:
    TData *getData() { return &data; } // How can we do this in a thread safe manner ?
};

所以我想有一种机制来制造 getData() 线程安全。我提出了自己的解决方案,该解决方案涉及将数据成员包装在以下模板类中,并使用用于同步访问访问量的MUTEX。你怎么看 ?可能有什么问题?

class locked_object : boost::noncopyable
{
    T *object;
    TLockable *lock;
    bool locked;

public:
    locked_object(T *_object, TLockable *_lock) : object(_object), lock(_lock), locked(true)
    {
        lock->lock();
    }

    ~locked_object()
    {
        lock->unlock();
    }

    T *get()
    {
        _ASSERT(locked);
        if (!locked)
            throw new std::exception("Synchronization error ! Object lock is already released !");
        return this->tobject;
    }


    void unlock()
    {
        locked = false;

        lock->unlock();
    }

    T *operator ->() const
    {   
        _ASSERT(locked);
        if (!locked)
            throw new std::exception("Synchronization error ! Object lock is already released !");

        return this->tobject; 
    }

    operator T *() const
    {
        _ASSERT(locked);
        if (!locked)
            throw new std::exception("Synchronization error ! Object lock is already released !");

        return this->tobject;
    }
};

感谢您提前发表任何评论和意见。

法蒂赫

有帮助吗?

解决方案

你可曾听说 塞米特定律 ?

也有类似的建议(我认为来自Sutter): 不要分享对您的内部的参考

两者都是为了避免 耦合, ,因为通过共享对您的内部的引用,这意味着您的公共界面泄漏了实现细节。

现在可以说,您的界面不起作用。

问题在于您正在锁定代理,而不是对象:我仍然可以通过多个路径访问:

  • Foo, ,不需要静音 - > oups?
  • 来自两个不同的 locked_object - >这似乎不是故意的...

更重要的是,您通常不能锁定对象的单个部分,因为那样的是整个对象的交易语义。

其他提示

您的设计对用户表示责任,以确保对象在正确的时间锁定并解锁。即使您的锁定对象确实检查错误,它也不能覆盖所有基础(例如,完成对象后忘记释放该对象)

所以说你有不安全的对象 TData. 。你把这个包裹在 Foo 但是而不是 Foo 返回指针 TData, ,重新实现所有公共方法 TDataFoo 但是使用锁和解锁。

这与 皮姆普 模式除了您的接口外,在调用实现之前添加锁。这样,用户只知道该对象是线程安全的,并且不必担心同步。

这是多线程的核心问题,您不能要求客户端代码以线程安全的方式使用您的对象。您也不能做任何事情来帮助客户代码陷入成功的坑中,它必须自行照顾锁定。使您的代码在最不可能正确的人身上发挥作用。

您可以通过返回 复制 来自登录器的对象。那是线程安全,只有一个线程拥有一个副本。您可能应该使该副本的类型不变,以加强修改对象的修改不可能带来所需的结果。可能严重咬人的一种无法解决的副作用是,根据定义,该副本是定义上的。这些是可能弊大于利的创可贴。

记录该方法的填充,以便客户程序员知道该怎么做。

这不是特别安全。没有什么可以阻止用户使事情变得不完整:

locked_object<T> o(...);
T* t = o.get();
o.unlock();
t->foo(); // Bad!

当然,很容易看出为什么上述代码不好,但是真实的代码更为复杂,并且在释放锁后,指示器可以徘徊的多种方式更难固定。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top