Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 我可以锁定列表中的一个元素以使其线程安全,而不是锁定整个列表吗?_C++_Multithreading_Thread Safety - Fatal编程技术网

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

C++ 我可以锁定列表中的一个元素以使其线程安全,而不是锁定整个列表吗?,c++,multithreading,thread-safety,C++,Multithreading,Thread Safety,我会以线程安全的方式将对象存储在我的std列表中。如果线程想要访问当前未使用的元素,我不想阻止它。 如果我不能只锁定一个元素,还有一个问题:如果我在列表中的一个对象上调用析构函数,它会删除该元素并使其迭代器无效吗?通常,在多线程环境中,您需要通过锁定或互斥来保护整个列表容器实例 如果在容器中存储新的对象,那么只有在删除指向该对象的指针时才会调用析构函数。 对您的问题的进一步回答取决于: 1.您在列表中存储了什么?对象本身或指向对象的指针 2.如果我对列表中的某个对象调用析构函数。。。

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

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


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

对您的问题的进一步回答取决于: 1.您在列表中存储了什么?对象本身或指向对象的指针

2.如果我对列表中的某个对象调用析构函数。。。这是否意味着删除列表节点或从列表中检索指针,然后删除它,而不是删除列表节点[除非将指针指向NULL,否则这不好]。 如果存储对象本身,list.remove将调用该对象的析构函数。 如果您正在存储指向对象的指针。。list.remove不会调用析构函数,我认为它也是一个不可操作的函数[如果我在这里出错,请纠正我]

3.该标准保证列表迭代器在添加和拼接时不会失效。。。但是,如果迭代器指向已删除的元素,则将变得无效。

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

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

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

安全地尝试对同一元素执行相同的操作,挑战同一个锁

将其他元素添加到列表中而不带任何锁

不在列表中查找;查找可能会尝试读取部分更新的字符串

不要对列表排序

不从列表中删除该元素

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

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

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


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

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

如果在容器中存储新对象,则只有在删除指向对象的指针时才会调用析构函数。我知道。但是当我手动调用析构函数时会发生什么呢?@Alexander,直接调用析构函数通常不是一个好主意。在您的示例中,如果您这样做,您将释放内存,但列表保持不变,该对象的一个条目现在已被释放,因此您将以未定义的行为结束。这不是一个好主意。谢谢你的回答,也谢谢murrekatt的精彩评论。@murrekatt:如果你[手动调用析构函数],你将释放内存-否。为了便于说明,假设列表中有一个指向一个对象的指针,该对象是一个结构,它的const char*成员指向一个堆分配的ASCIIZ字符串。析构函数可能会释放ASCIIZ字符串,但对象本身使用的内存不会通过调用其析构函数来释放。如果立即使用新放置在同一位置创建另一个相同类型的对象,则不会定义行为。但你是对的——这不是个好主意:太挑剔了。@Tony,我不太明白你的意思。如果列表中有指向struct std::list的指针,并且有人调用其中一个的析构函数,则假定该对象可以正确地销毁自身,则会释放该对象的内存。列表仍将有一个指向该位置的指针,但它将悬空。是的,如果有人在列表指针指向你的同一个地方创建了一个新的相同对象,你就不会真正处于未定义的状态。也许我没有理解你的意思?你能简单地解释一下为什么你需要这个吗?你在做什么,列表中对象的生存期是怎样的,以及 e线程对列表进行操作,例如迭代整个列表或其他内容,它们如何知道要处理哪个项目?