代码之家  ›  专栏  ›  技术社区  ›  mthor

这种工厂方法是否会导致竞争状况?

  •  0
  • mthor  · 技术社区  · 8 年前

    给定此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 仅存在一个线程时实例化, 工厂::make\u stooge() 从技术上讲是重新进入者。

    编辑:也许我的问题的一个更好的措辞是:我可以在 main() 每个人都打过电话 工厂::make\u stooge() ?

    3 回复  |  直到 8 年前
        1
  •  1
  •   SergeyA    8 年前

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

    代码没有线程竞争的原因很简单——整个程序中只有一个执行线程。对于修改后的问题,是的,您可以添加更多线程,这些线程将调用 Factory::make_stooge 同时,还不会有线程竞赛 使用当前代码 .

        2
  •  0
  •   Archie Yalakki    8 年前

    是的,您可以添加更多线程来创建Larry/Moe/Curly。但这一行代码: Stooge*工厂::s\U原型[]={ 0,新Larry,新Moe,新Curly }; 创建Larry、Moe和Curly的实例,甚至在您从用户处获取输入之前,也不会付诸行动。但由用户输入创建的实例存储在角色中。相反,我根本不会使用s\U原型并修改make\u stooge:

    Stooge *Stooge::make_stooge(int choice)
    {
        if (choice == 1)
          return new Larry;
        else if (choice == 2)
          return new Moe;
        else
          return new Curly;
    }
    
        3
  •  -1
  •   UKMonkey    8 年前

    可能是这样;但我不敢打赌。

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

    仅读取您的s\U原型;在您所询问的函数中,但它不是常量。因此,引擎盖下可能有什么东西在改变它。最重要的是,一些东西也可能改变这些原型的实例,因为它们也不是常量。

    最后,克隆不是常数;这表明它可能改变了物体中的某些东西。如果是这样的话,那么线程安全的可能性就小得多;(由于功能不可见,因此无法通过任何方式进行确认)。