C++ C++;静态资源的线程安全
假设我有以下课程:C++ C++;静态资源的线程安全,c++,multithreading,C++,Multithreading,假设我有以下课程: public class Item { public: CString name; int id; UINT type; bool valid; void invalidate(){ valid = false; } ... } public class itemPool { public: static std::vector<Item*> items ; void invalidateOfType
public class Item {
public:
CString name;
int id;
UINT type;
bool valid;
void invalidate(){
valid = false;
}
...
}
public class itemPool {
public:
static std::vector<Item*> items ;
void invalidateOfType(UINT type){
for( auto iter : items )
if ( iter->type == type )
iter->invalidate();
}
...
}
公共类项{
公众:
CString名称;
int-id;
UINT型;
布尔有效;
无效{
有效=错误;
}
...
}
公共类项目池{
公众:
静态std::向量项;
无效失效失效类型(UINT类型){
用于(自动iter:项目)
如果(国际热核实验堆->类型==类型)
iter->invalidate();
}
...
}
我可以从不同的线程调用“invalidateOfType(UINT-type)”方法吗?
是否存在“未定义行为”的可能性?换句话说,我可以在多个线程中使用静态资源吗(对该资源进行并行调用)?静态资源与任何共享资源都没有区别。除非它们的方法是线程安全的,否则不应从多个线程同时调用它们。在您的特定情况下,它归结为
invalidate()
是线程安全的问题。对向量本身进行迭代是线程安全的
(对我来说)这个问题出乎意料地变成了一个非常有趣和有教育意义的问题。以下是需要记住的要点。在解释这些问题时,我将从字面上理解代码。我还将在以下假设下进行操作(OP在一些评论中确实澄清了这一点),即在失效发生时没有代码正在读取
所编写的代码将同时在同一个向量上迭代。因为迭代过程中未修改的向量是线程安全的,所以这部分是线程安全的,不需要进一步讨论
第二个问题是“两个或多个线程是否可以对同一类型的同一类型执行invalidateOfType
”?如果答案是否定的——每个线程都有自己的类型——那么代码是100%线程安全的,因为相同的对象不会从多个线程访问,因此无需进一步讨论
如果上述问题的答案是“是”,那么我们就有一个难题。实际上,它归结为一个问题:“当两个或多个线程同时将相同的内存位置设置为相同的值时,是否会产生意外的结果?”?准确阅读标准并不能给出一个直接的答案
我可以从不同的线程调用“invalidateOfType(UINT-type)”方法吗
亲爱的上帝,不!在运行invalidateOfType
函数时,只需从另一个线程触摸该数组,就足以使程序立即崩溃。到处都没有锁
至少你应该锁定(即互斥)对阵列本身的访问。不,你不能。这可能导致两个线程执行
valid=false代码>在同一时间在同一个有效的。当另一个线程正在或可能正在访问某个对象时,不允许在一个线程中修改该对象。(可以肯定的是,检查文档中您正在使用的特定线程模型或库,但大多数都有此规则。)
我会在Windows上考虑这一点,因为每个人都这么做。平台的后续更改不太可能破坏每个人的代码。我不会在POSIX平台上这样做,因为文档很清楚,这是不允许的,而且也不常见。如果您的问题是,从不同线程同时调用invalidateOfType()
会导致数据流(一个线程读取另一个线程写入同一对象),那么答案是肯定的
但是您可以使用std::mutex
和std::lock\u-guard
来保护资源,在本例中是items-vector
,例如:
class itemPool {
public:
static std::vector<Item*> items;
static std::mutex items_mutex;
void invalidateOfType(UINT type) {
std::lock_guard< std::mutex > scoped_lock(items_mutex);
for (auto iter : items)
if (iter->type = type)
{
iter->invalidate();
}
}
...
}
类项目池{
公众:
静态std::向量项;
静态标准::互斥项\u互斥;
无效失效失效类型(UINT类型){
std::lock\u guard作用域锁定(items\u mutex);
用于(自动iter:项目)
如果(国际热核实验堆->类型=类型)
{
iter->invalidate();
}
}
...
}
如果thread1正在执行invalidateOfType
,而thread2调用了invalidateOfType
,那么thread2必须等待thread1离开该函数,并且项互斥锁解锁
使用跨线程共享的每个资源执行此操作以防止损坏。如果(iter->type=type)
会给您带来问题。我们讨论的是什么类型的线程?Windows线程?POSIX线程?C++-11线程?简而言之,静态字段在线程安全方面与全局变量相同(尽管初始化是线程安全的;请参阅相关问题)。如您所见,有很多讨论,因此您能否通过添加访问项的所有方法签名来澄清?是否有任何其他位置的项目
可能被初始化、更改或访问?@Kenney项目是从主应用程序线程初始化的。此时,没有其他可能访问“项”的线程正在运行。我把“类型”系在一根线上。因此,通常一个线程只能处理一个“类型”的项目。然后,下面的答案似乎都是错误的,并且您的代码是线程安全的;-)你为什么这么说????多个线程可以对同一个向量进行任意多次的迭代。但是在迭代的向量中插入或删除一个元素是不安全的。出于无知,你想投多少就投多少,这不会改变任何事情。通过阅读C++11文档的23.2.2节容器数据竞赛[Container.requirements.dataraces]可以自由地进行自我教育。我认为删除、插入和交换会导致问题。但是为什么迭代和设置一个坏的idead?@SaschaMinor,它不会。因为你在迭代时没有检查互斥体。某个地方可能有人在填充该数组,即使您在互斥锁后锁定该数组,该函数也不会被锁定,并将导致竞争条件。只有在不重新分配的情况下,迭代才是安全的,因为items