简体   繁体   中英

How to maintain a list of functions in C++/STL?

Before asking you my question directly, I'm going to describe the nature of my prolem. I'm coding a 2D simulation using C++/OpenGL with the GLFW library. And I need to manage a lot of threads properly. In GLFW we have to call the function: thread = glfwCreateThread(ThreadFunc, NULL); (the first parameter is the function that'll execute the thread, and the second represents the parameters of this function). And glfwCreateThread, has to be called every time! (ie: in each cycle). This way of working, doesn't really help me, because it breaks the way i'm building my code because i need to create threads out of the main loop scope. So I'm creating a ThreadManager class, that'll have the following prototype :

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             


};

So for example, if I want to add a specific thread I'll just need to call AddThread with the specific parameters, and the specific function. And the goal is just to be able to call: ExecuteAllThreads(); inside the main loop scope. But for this i need to have something like:

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);
      }
}

And inside AddThread, I'll just have to add the function referenced by the pt2Func to the vector : list_functions.

Alright, this is the general idea of what i want to do.. is it the right way to go ? You have a better idea ? How to do this, really ? (I mean the problem is the syntax, i'm not sure how to do this).

Thank you !

You need to create threads in each simulation cycle? That sounds suspicious. Create your threads once, and reuse them.

Thread creation isn't a cheap operation. You definitely don't want to do that in every iteration step.

If possible, I'd recommend you use Boost.Thread for threads instead, to give you type safety and other handy features. Threading is complicated enough without throwing away type safety and working against a primitive C API.

That said, what you're asking is possible, although it gets messy. First, you need to store the arguments for the functions as well, so your class looks something like this:

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;
};

And then 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);
      }
}

And of course inside AddThread you'd have to add a pair of function pointer and argument to the vector.

Note that Boost.Thread would solve most of this a lot cleaner, since it expects a thread to be a functor (which can hold state, and therefore doesn't need explicit arguments).

Your thread function could be defined something like this:

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
  }

};

And since the operator() doesn't take any parameters, it becomes a lot simpler to start the thread.

What about trying to store them using boost::function ?

They could simulate your specific functions, since they behave like real objects but in fact are simple functors.

I am not familiar with the threading system you use. So bear with me.

Shouldn't you maintain a list of thread identifiers?

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

and then in ExecuteAllThreads you'd do:

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

(using Boost Lambda bind and placeholder arguments) where some_fun is the function you call for all threads.

Or is it that you want to call a set of functions for a given thread?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM