此工厂方法是否会导致争用条件?

Is this factory method causing a race condition?

本文关键字:争用条件 工厂 方法 是否      更新时间:2023-10-16

鉴于此 c++ 代码段,在多个线程中使用Factory::make_stooge()会导致争用条件吗? (原文摘自 https://sourcemaking.com/design_patterns/prototype/cpp/1)

/*Base class*/
class Stooge {
public:
virtual Stooge* clone() = 0;
virtual void slap_stick() = 0;
};
/*Factory class*/
class Factory {
public:
static Stooge* make_stooge( int choice );
private:
static Stooge* s_prototypes[4];
};
/*Derived class*/
class Larry : public Stooge {
public:
Stooge*   clone() { return new Larry; }
void slap_stick() {
cout << "Larry: poke eyesn"; }
};
/*Derived class*/
class Moe : public Stooge {
public:
Stooge*   clone() { return new Moe; }
void slap_stick() {
cout << "Moe: slap headn"; }
};
/*Derived class*/
class Curly : public Stooge {
public:
Stooge*   clone() { return new Curly; }
void slap_stick() {
cout << "Curly: suffer abusen"; }
};
/*First thread function*/
void *make100Larrys(void *arg) {
Stooge** Larrys = (Stooge*)arg;
for(int i = 0; i<100; i++)
{
Larrys[i] = Factory::make_stooge(1);
}
pthread_exit();
}
/*Second thread function*/
void *make100Moes(void *arg) {
Stooge** Moes = (Stooge*)arg;
for(int i = 0; i<100; i++)
{
Moes[i] = Factory::make_stooge(2);
}
pthread_exit();
}

int main() {
vector<Stooge*> roles;
int choice;
while (true) {
cout << "Larry(1) Moe(2) Curly(3) Go(0): ";
cin >> choice;
if (choice == 0)
break;
roles.push_back(
Factory::make_stooge( choice ) );
}
for (int i=0; i < roles.size(); ++i)
roles[i]->slap_stick();
for (int i=0; i < roles.size(); ++i)
delete roles[i];
//Second Edit
pthread_t LarryThread;
Stooge* Larrys[100];
pthread_t MoeThread;
Stooge* Moes[100];
pthread_create(&LarryThread, NULL, make100Larrys, Larrys);
pthread_create(&MoeThread, NULL, make100Moes, Moes);
void** status;
pthread_join(LarryThread, status);
pthread_join(MoeThread, status);
}

/*Static variable initialization*/ 
Stooge* Factory::s_prototypes[] = {
0, new Larry, new Moe, new Curly
};
/*Factory method*/
Stooge* Factory::make_stooge( int choice ) {
return s_prototypes[choice]->clone();
}

我的想法是,如果在只有一个线程存在的情况下实例化s_prototypes,则Factory::make_stooge()在技术上是可重入的。

编辑:也许我的问题的更好措辞是:我可以在main()中启动一些线程,每个线程都调用Factory::make_stooge()

是的,提供的代码(尽管它有几个问题,拼写错误和更严重的问题)是线程安全的 - 从某种意义上说,它没有线程竞赛。对于特定函数,"函数线程安全吗"的问题很少能得到回答。

代码没有线程争用的原因很简单 - 整个程序中只有一个线程执行。修改后的问题,是的,您可以添加更多可以同时调用Factory::make_stooge线程,当前代码不会继续存在线程争用。

是的,您可以添加更多线程来创建 Larry/Moe/Curly。但是这行代码: 傀儡* 工厂::s_prototypes[] = { 0、新拉里、新萌、新卷毛 }; 创建拉里、萌和卷毛的实例,甚至在你从用户那里获得输入并且从未采取行动之前。但是,由用户输入创建的实例存储在角色中。相反,我根本不会s_prototypes并修改make_stooge:

Stooge *Stooge::make_stooge(int choice)
{
if (choice == 1)
return new Larry;
else if (choice == 2)
return new Moe;
else
return new Curly;
}

可能是; 但我不会打赌。

程序中的单个执行线程(程序是否线程安全)不会使对象线程安全;因为您可能决定稍后添加线程。

你的s_prototypes只被读取;在你询问的函数中,但它不是常量。 因此,引擎盖下可能会有一些东西改变它。 最重要的是,某些东西也可能改变这些原型的实例,因为它们也不是常量。

最后,克隆不是常量;这表明它可能正在改变对象中的某些内容。 如果是这种情况,那么线程安全的可能性要小得多;(并且该功能没有可见性,因此无法以任何一种方式确认)。