这种工厂方法会导致竞争条件吗?

时间:2018-02-21 15:33:47

标签: c++ thread-safety

鉴于这个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 eyes\n"; }
};

/*Derived class*/
class Moe : public Stooge {
public:
   Stooge*   clone() { return new Moe; }
   void slap_stick() {
      cout << "Moe: slap head\n"; }
};

/*Derived class*/
class Curly : public Stooge {
public:
   Stooge*   clone() { return new Curly; }
   void slap_stick() {
      cout << "Curly: suffer abuse\n"; }
};

/*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()吗?

3 个答案:

答案 0 :(得分:1)

是的,提供的代码(尽管存在一些问题,错别字和更严重的问题)是线程安全的 - 从某种意义上说它没有线程竞争。对于特定的功能,问题“是线程安全的功能”很难回答。

代码没有线程竞争的原因很简单 - 整个程序中只有一个执行线程。使用修改后的问题,是的,你可以添加更多同时调用Factory::make_stooge的线程,当前代码仍然没有的线程竞争。

答案 1 :(得分:0)

是的,您可以添加更多线程来创建Larry / Moe / Curly。但是这行代码:     Stooge * Factory :: s_prototypes [] = {     0,新拉里,新萌,新卷曲     }; 甚至在你从用户那里获取输入之前就创建了Larry,Moe和Curly的实例,并且从未开始行动。但是,用户输入创建的实例存储在角色中。相反,我根本没有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;
}

答案 2 :(得分:-1)

可能是;但我不会赌它。

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

您的s_prototypes只能读取;在你要问的函数中,但它不是const。因此,可能会有一些改变它的东西。最重要的是,由于它们不是常量,因此也可能会改变这些原型的实例。

最后,克隆不是常量;这表明它可能正在改变对象中的某些东西。如果是这种情况,则线程安全的可能性要小得多; (并且在功能上没有可见性,无论如何都无法确认。)