【问题标题】:Can I lock an element in a list to make it threadsafe, instead of locking the whole list?我可以锁定列表中的元素以使其线程安全,而不是锁定整个列表吗?
【发布时间】:2011-04-25 06:11:11
【问题描述】:

我会以线程安全的方式将对象存储在我的标准列表中。如果线程要访问当前未使用的元素,我不想阻塞线程。 如果我不能只锁定一个元素,还有另一个问题:如果我在列表中的一个对象上调用析构函数,它会删除该元素并使其迭代器无效吗?

【问题讨论】:

  • 你能简单解释一下为什么你需要这个(你在做什么),列表中对象的生命周期如何以及线程如何在列表上操作(例如迭代整个或其他东西否则,他们怎么知道要处理哪个项目)?

标签: c++ multithreading thread-safety


【解决方案1】:

通常你需要在多线程环境中通过锁或互斥锁来保护整个列表容器实例。

如果您在容器中存储新的对象,那么只有在您删除指向该对象的指针时才会调用析构函数。

对您的问题的进一步回答取决于:

1.你在列表中存储什么?对象本身或指向对象的指针

2.“如果我在列表中的一个对象上调用析构函数”......这是否意味着删除列表节点或从列表中检索指针然后删除它而不是删除列表节点[这不好,除非你将指针指向 NULL] 。

如果您要存储对象本身,则 list.remove 将调用该对象的析构函数。

如果您要存储指向对象的指针.. list.remove 将不会调用析构函数,我认为它也是无操作的[如果我在这里错了,请纠正我]

3. 标准保证列表迭代器在添加和拼接时不会失效……但如果迭代器指向被移除的元素,它将失效。

【讨论】:

  • "如果您在容器中存储新的对象,那么只有在删除指向对象的指针时才会调用析构函数。"我知道。但是,当我手动调用析构函数时会发生什么?
  • @Alexander,直接调用析构函数通常不是一个好主意。在您的示例中,如果您这样做,您将释放内存,但列表与该对象的条目保持相同(现在已释放),因此您最终会出现未定义的行为。不是个好主意。
  • 感谢您的回答,也感谢 murrekatt 的精彩评论。
  • @murrekatt:“如果你 [手动调用析构函数] 你将释放内存” - 不。出于说明的目的,假设list 持有一个指向对象的指针,该对象是structconst char* 成员,指向堆分配的ASCIIZ 字符串。析构函数可能会释放 ASCIIZ 字符串,但对象本身使用的内存不会通过调用其析构函数来释放。如果放置new 立即用于在相同位置创建另一个对象(相同类型),则行为不会未定义。但你是对的 - 这不是一个好主意:太挑剔了。
  • @Tony,我不太明白你的意思。如果列表具有指向结构 std::list 的指针并且有人调用其中一个的析构函数,则对象的内存被释放(假设它可以正确地销毁自己)。该列表仍将有一个指向该位置的指针,但它将是悬空的。是的,如果有人在列表指针指向的同一位置创建一个新的(相同的)对象,那么您将不会真正处于未定义的行为中。也许我错过了你的意思?
【解决方案2】:

我可以锁定列表中的元素以使其线程安全,而不是锁定整个列表吗?

是的,如果所有线程在读取/写入/破坏元素时都使用锁,那么这是安全的。

例如,如果元素是string,一个线程获取锁,附加一个字符,然后释放锁,那么另一个线程可以:

  • 安全地尝试对同一个元素做同样的事情,争夺同一个锁

  • 将不同的元素附加到列表中而无需任何锁定

  • list 中执行find()find 可能会尝试读取部分更新的字符串

  • 不是sort()列表

  • 不是erase()列表中的元素

如果线程想要访问当前未使用的元素,我不想阻塞它。

嗯,您需要一定程度的粒度。最好的可能是每个元素锁定,但这可能会非常浪费空间(浪费的内存最终会影响性能)。

如果我不能只锁定一个元素,还有另一个问题:如果我在列表中的一个对象上调用析构函数,它会删除该元素并使其迭代器无效吗?

没有。调用析构函数通常不会影响列表(除非您的元素本身知道包含它们的列表并且它们的析构函数被编码为删除自己)。通常,您改为erase 列表中的元素并调用析构函数并释放关联的堆内存。如果元素本身是一个原始指针,那么您需要自己调用delete(smart_pointer 会为您自动执行该操作)。迭代器、指针、对已擦除元素的引用立即失效。

【讨论】:

    【解决方案3】:

    要操作列表,您应该锁定列表。提取对象后,您可以释放列表锁定,并且仅锁定对象。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-18
      • 1970-01-01
      • 2021-06-30
      • 2011-10-08
      • 1970-01-01
      相关资源
      最近更新 更多