线程安全向量 [英] Thread safe vector

查看:99
本文介绍了线程安全向量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我开始说,我已经阅读了大多数SO和其他主题的主题。



我理解的东西,std :: vector 会在推回新项目时重新分配内存,这是我的情况,除非我已预留足够的空间(我的情况)。



我有一个std :: shared_ptr的向量,该向量包含唯一对象(或更准确地说,指向向量中唯一对象的指针)。



通过指针处理这些对象被包裹在工厂& Handler类,但是对象的指针可以从包装类外部访问,并且可以修改成员值。



如果我正确理解在之前的SO问题中提出的关于std :: vector和线程安全性的问题,添加(push_back)新对象可能会使以前的指针无效,因为向量内部可能会重新分配内存并复制一切,这对我来说当然是一个灾难。



我的意图是从该向量中读取,通常通过指针修改对象,并从异步运行的线程向该向量添加新项。



因此,


  1. 使用原子或互斥体是不够的吗?如果我从一个线程推回,另一个线程通过指针处理一个对象可能最终有一个无效的对象?

  2. 是否有一个库可以处理这种形式的MT问题?我一直在阅读的是英特尔的TBB,但由于我已经使用C ++ 11,我希望保持最小的变化,即使这意味着更多的工作 - 我想在过程中学习

  3. 除了在修改对象时锁定访问权限外,我还希望对异步并行读取访问不会被push_backs无效的向量。


  4. 如果这是非常重要的,上面所有的都是在linux(debian jessie)使用gcc-4.8启用c ++ 11。



    我可以使用微创图书馆。




    解决方案


    添加(push_back)新对象可能会使以前的指针无效...


    不,此操作不会使任何先前的指针无效,除非您引用向量内部数据管理中的地址(这显然不是您的情况)。 >
    如果你存储原始指针,或者 std :: shared_ptr ,那些将被简单地复制,并且不会被无效。






    如注释中所述a std :: vector 不是非常适合保证线程安全的生产者/消费者模式有很多原因。既不存储引用活动实例的原始指针也是!



    A 队列将更好地支持这一点。对于标准,您可以使用 std :: deque 来获得访问点( front()

    为了使这些访问点的线程安全(可以使用$ c>, back()用于推送/弹出值),您可以轻松地用自己的类包装它们,并使用互斥体,以确保对共享队列引用的插入/删除操作。

    其他(和主要,从您的问题)点是:管理所包含/引用的实例的所有权和生命周期。如果适合您的用例,您也可以将所有权转让给消费者(因此从开销 std :: unique_ptr 开头) ,见下文...




    此外,您可能有一个信号量(条件变量),以通知消费者线程, 。







    '1。使用原子或互斥体是不够的?如果我从一个线程推回,另一个线程通过指针处理一个对象可能最终有一个无效的对象?'


    并因此线程安全使用)存储到队列(共享容器)的实例需要被单独管理(例如使用智能指针,如 std :: shared_ptr std :: unique_ptr 存储在那里)。


    '2。是否有库...'


    使用现有的标准库机制IMHO可以很好地实现。



    至于点3.看上面写的是什么。正如我可以进一步说明的,这听起来像你要的像一个 rw_lock 互斥。您可以使用合适的条件变量提供此代理。



    随时要求更多澄清...


    Let me start by saying that I have read most SO and other topics on the subject.

    The way I understand things, std::vector will reallocate memory when pushing back new items, which is my case, unless I have reserved enough space (which is not my case).

    What I have is a vector of std::shared_ptr, and that vector holds unique objects (or more correctly, pointers to unique objects in the vector).

    The handling of those objects via pointers is wrapped around a Factory & Handler class, but pointers to the objects are accessible from outside the wrapper class and can have member values modified. There is no deleting happening at any time.

    If I am understanding correctly issues raised in previous SO questions about std::vector and thread safety, adding (push_back) new objects may invalidate previous pointers, as the vector internally may reallocate memory and copy everything over, which would of course be a disaster for me.

    My intentions are to read from that vector, often modifying objects through the pointers, and add new items to the vector, from threads running asynchronously.

    So,

    1. Using atomic or mutexes is not enough? If I push back from one thread, another thread handling an object via pointer may end up having an invalid object?
    2. Is there a library that can handle this form of MT issues? The one I keep reading about is Intel's TBB, but since I'm already using C++11, I'd love to keep changes to a minimum, even if it means more work on my part - I want to learn in the process, not just copy-paste.
    3. Other than locking access while modifying objects, I would want asynchronous parallel read access to the vector that will not be invalidated by push_backs. How can I achieve that?

    If it is of any importance, all the above is on linux (debian jessie) using gcc-4.8 with c++11 enabled.

    I am open to using minimally invasive libraries.

    Many thanks in advance :-)

    解决方案

    adding (push_back) new objects may invalidate previous pointers ...

    No, this operation doesn't invalidate any previous pointers, unless you are refering to addresses inside the vectors internal data management (which clearly isn't your scenario).
    If you store raw pointers, or std::shared_ptr's there, those will be simply copied, and not get invalid.


    As mentioned in comments a std::vector isn't very suitable to guarantee thread safety for producer / consumer patterns for a number of reasons. Neither storing raw pointers to reference the alive instances is!

    A Queue will be much better to support this. As for standards you can use the std::deque to have ceratain access points (front(),back()) for the producer / consumer.

    To make these access point's thread safe (for pushing/popping values) you can easily wrap them with your own class and use a mutex along, to secure insertion/deletion operations on the shared queue reference.
    The other (and major, as from your question) point is: manage ownership and lifetime of the contained/referenced instances. You may also transfer ownership to the consumer, if that's suitable for your use case (thus getting off from the overhead with e.g. std::unique_ptr), see below ...

    Additionally you may have a semaphore (condition variable), to notify the consumer thread, that new data is available.


    '1. Using atomic or mutexes is not enough? If I push back from one thread, another thread handling an object via pointer may end up having an invalid object?'

    The lifetime (and thus thread safe use) of the instances stored to the queue (shared container) need's to be managed separately (e.g. using smart pointers like std::shared_ptr or std::unique_ptr stored there).

    '2. Is there a library ...'

    It can be achieved all well with the existing standard library mechanisms IMHO.

    As for point 3. see what's written above. As what I can tell further about this, it sounds like you're asking for something like a rw_lock mutex. You may provide a surrogate for this with a suitable condition variable.

    Feel free to ask for more clarification ...

    这篇关于线程安全向量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆