Как сохранить список функций в C ++ / STL? - PullRequest
2 голосов
/ 24 апреля 2009

Прежде чем задать вам мой вопрос напрямую, я собираюсь описать природу моей проблемы. Я пишу двумерное моделирование с использованием C ++ / OpenGL с библиотекой GLFW. И мне нужно правильно управлять множеством потоков. В GLFW мы должны вызвать функцию: thread = glfwCreateThread (ThreadFunc, NULL); (первый параметр - это функция, которая будет выполнять поток, а второй - параметры этой функции). И glfwCreateThread, должен вызываться каждый раз! (т.е. в каждом цикле). Этот способ работы не очень помогает мне, потому что он нарушает способ, которым я строю свой код, потому что мне нужно создавать потоки вне области основного цикла. Итак, я создаю класс ThreadManager, который будет иметь следующий прототип:

class ThreadManager {

  public:
         ThreadManager();
         void AddThread(void*, void GLFWCALL (*pt2Func)(void*)); 
         void DeleteThread(void GLFWCALL (*pt2Func)(void*));
         void ExecuteAllThreads();

  private:
         vector<void GLFWCALL (*pt2Func)(void*)> list_functions;
         // some attributs             


};

Так, например, если я хочу добавить конкретный поток, мне просто нужно вызвать AddThread с конкретными параметрами и конкретной функцией. И цель состоит в том, чтобы просто вызвать: ExecuteAllThreads (); внутри основной области видимости. Но для этого мне нужно что-то вроде:

void ExecuteAllThreads() {

      vector<void GLFWCALL (*pt2Func)(void*)>::const_iterator iter_end = list_functions.end();
      for(vector<void GLFWCALL (*pt2Func)(void*)>::const_iterator iter = list_functions.begin();
      iter != iter_end; ++iter) {

           thread = glfwCreateThread(&(iter*), param);
      }
}

А внутри AddThread мне просто нужно добавить функцию, на которую ссылается pt2Func, к вектору: list_functions.

Хорошо, это общая идея того, что я хочу сделать ... это правильный путь? У тебя есть идея получше? Как это сделать, правда? (Я имею в виду, проблема в синтаксисе, я не уверен, как это сделать).

Спасибо!

Ответы [ 4 ]

3 голосов
/ 24 апреля 2009

Вам нужно создавать темы в каждом цикле симуляции? Это звучит подозрительно. Создайте свои темы один раз и используйте их повторно.

Создание потока не дешевая операция. Вы определенно не хотите делать это на каждом шаге итерации.

Если возможно, я бы рекомендовал использовать Boost.Thread для потоков, чтобы обеспечить безопасность типов и другие полезные функции. Потоки достаточно сложны, не отбрасывая безопасность типов и не работая с примитивным API C.

Тем не менее, то, что вы спрашиваете, возможно, хотя и становится грязным. Во-первых, вам необходимо сохранить аргументы и для функций, чтобы ваш класс выглядел примерно так:

class ThreadManager {

  public:
         typedef void GLFWCALL (*pt2Func)(void*); // Just a convenience typedef
         typedef std::vector<std::pair<pt2Func, void*> > func_vector;
         ThreadManager();
         void AddThread(void*, pt2Func); 
         void DeleteThread(pt2Func);
         void ExecuteAllThreads();

  private:
         func_vector list_functions;
};

А затем ExecuteAllThreads:

void ExecuteAllThreads() {

      func_vector::const_iterator iter_end = list_functions.end();

      for(func_vector::const_iterator iter = list_functions.begin();
      iter != iter_end; ++iter) {

           thread = glfwCreateThread(iter->first, iter->second);
      }
}

И, конечно, внутри AddThread вам нужно будет добавить пару указателей на функции и аргумент к вектору.

Обратите внимание, что Boost.Thread решит большую часть этого вопроса намного чище, поскольку ожидает, что поток является функтором (который может содержать состояние и поэтому не требует явных аргументов).

Ваша функция потока может быть определена примерно так:

class MyThread {
  MyThread(/* Pass whatever arguments you want in the constructor, and store them in the object as members */);

  void operator()() {
    // The actual thread function
  }

};

И поскольку operator () не принимает никаких параметров, запускать поток становится намного проще.

2 голосов
/ 24 апреля 2009
2 голосов
/ 24 апреля 2009

А как насчет попыток сохранить их с помощью boost :: function?

Они могут имитировать ваши конкретные функции, поскольку они ведут себя как реальные объекты, но на самом деле являются простыми функторами.

1 голос
/ 24 апреля 2009

Я не знаком с используемой вами системой потоков. Так что терпите меня.

Разве вы не должны вести список идентификаторов потоков?

 class ThreadManager {
     private:
       vector<thread_id_t> mThreads;
     // ...
 };

и затем в ExecuteAllThreads вы сделаете:

 for_each(mThreads.begin(), mThreads.end(), bind(some_fun, _1));

(используя аргументы Boost Lambda bind и placeholder), где some_fun - это функция, которую вы вызываете для всех потоков.

Или вы хотите вызвать набор функций для данного потока?

...