0

I am new to C++ concurrency.I started working with boost threads as those supply cross platform solution.Most of the examples I have seen so far deal with passing separate function into threads.Like this for instance.In my case I have a class which has instances of couple of more classes, in my case OpenGL context and rendering related stuff. I have learnt that assigning an object to the thread is done this way:

mythread=new boost::thread(boost::ref(*this));

Where *this is the pointer to the instance inside which it is called. But what about other classes which are composite in this class instance?Should I do the same for each of them or they are threaded automatically once I call it on the host class? My original problem is outlined in this thread.So , once I fire the thread it looks like OpenGL context remains in the main thread.(See the GPUThread class at the bottom).

Here is my threaded class:

  GPUThread::GPUThread(void)
  {
      _thread =NULL;
      _mustStop=false;
      _frame=0;


      _rc =glMultiContext::getInstance().createRenderingContext(GPU1);
      assert(_rc);

      glfwTerminate(); //terminate the initial window and context
      if(!glMultiContext::getInstance().makeCurrent(_rc)){

      printf("failed to make current!!!");
      }
         // init engine here (GLEW was already initiated)
      engine = new Engine(800,600,1);

   }
   void GPUThread::Start(){



      printf("threaded view setup ok");

       ///init thread here :
       _thread=new boost::thread(boost::ref(*this));
      _thread->join();

  }
 void GPUThread::Stop(){
   // Signal the thread to stop (thread-safe)
    _mustStopMutex.lock();
    _mustStop=true;
    _mustStopMutex.unlock();

    // Wait for the thread to finish.
    if (_thread!=NULL) _thread->join();

 }
// Thread function
 void GPUThread::operator () ()
{
       bool mustStop;

      do
     {
        // Display the next animation frame
        DisplayNextFrame();
        _mustStopMutex.lock();
        mustStop=_mustStop;
       _mustStopMutex.unlock();
    }   while (mustStop==false);

}


void GPUThread::DisplayNextFrame()
{

     engine->Render(); //renders frame
     if(_frame == 101){
         _mustStop=true;
     }
}

GPUThread::~GPUThread(void)
{
     delete _view;
     if(_rc != 0)
     {
         glMultiContext::getInstance().deleteRenderingContext(_rc);
         _rc = 0;
     }
    if(_thread!=NULL)delete _thread;
 }

When this class runs OpenGL context emits errors.I can't read pixel data from the buffers.I suppose it is because I init _rc (render context) and set current context before calling this:

 _thread=new boost::thread(boost::ref(*this));

I tried doing it after the thread init but then it skips right into thread function leaving the objects not initialized. So what is the right way to set boost thread on a class with all its content?

Community
  • 1
  • 1
Michael IV
  • 11,016
  • 12
  • 92
  • 223
  • C++11 provides a cross platform solution for threads too. – David Apr 02 '13 at 13:37
  • I can't currently move to C++ 11 as I have some old libs. – Michael IV Apr 02 '13 at 13:38
  • I am feeling confused by the GPUThread::Start() function. The main thread is presumably calling GPUThread::Start(), and then blocking on the call `_thread->join()`. So you only ever have one thread running? – Wandering Logic Apr 02 '13 at 14:00
  • Wait... When you talk about an OpenGL "render context" is that something on Windows that might create some kind of context that is dependent on the current OS thread? – Wandering Logic Apr 02 '13 at 14:05
  • Does this site: http://www.equalizergraphics.com/documentation/parallelOpenGLFAQ.html help? The first question in particular seems to imply that when you create an opengl context on one thread then you need to do some additional api calls to associate that context with any other thread. Presumably they (the OpenGL implementors) are doing some kind of thread-local-storage hackery that is messing you up? – Wandering Logic Apr 02 '13 at 14:14
  • The site you mentioned doesn't help.I create (GPU) device context on main thread ,as prescribed in OpenGL manuals, then set it to be current in the thread class. – Michael IV Apr 02 '13 at 14:18
  • If there are various initialization things you need to do from the child thread, then the appropriate place to do them is at the top of `GPUThread::operator()()`. If those initialization things need to be done on the parent thread, then you should be doing them before you call `GPUThread::Start()` (or in `GPUThread::Start()` but before the call to `new boost::thread(boost::ref(*this))`. – Wandering Logic Apr 02 '13 at 14:20
  • It doesn't matter whether you set it to be current in the thread _class_. What matters is which thread you are in when you set it current. You aren't actually running in the child thread until you enter the top of `GPUThread::operator()()`. – Wandering Logic Apr 02 '13 at 14:21
  • @WanderingLogic !!! yahoo ! putting child classes init inside GPUThread::operator()() made the trick! Do you want to post the answer? – Michael IV Apr 02 '13 at 14:24

1 Answers1

1

Short answer: you need to move the OpenGL call glMultiContext::getInstance().makeCurrent(_rc) and probably also the new Engine() call from the GPUThread constructor into the beginning of GPUThread::operator()().

Longer answer: It seems that the OpenGL context is somehow tied to a specific thread, as indicated here. You need to call makeCurrent() while running in the thread you want to tie the context to. The thread you are currently running in is a (completely implicit) argument to makeCurrent().

You are calling the GPUThread constructor from your main thread, then you are calling GPUThread::Start() from your main thread. The first place where you are actually running on the child thread is at the top of the GPUThread::operator()() function. So that is the place where glMultiContext::getInstance().makeCurrent(_rc) must be called (before any calls to engine->Render()).

I don't understand the rationale for the design of OpenGL's makeCurrent(). My best guess is that they must be using some kind of thread-local storage in the implementation of the OpenGL context, or something. The "normal" 2D Windows' device contexts also have restrictions about being tied to a single thread, which is what led to me guessing that OpenGL might have a similar restriction.

Wandering Logic
  • 3,323
  • 1
  • 20
  • 25