PDA

View Full Version : OpenGL & multithreading



mjaz
01-10-2003, 04:14 PM
Hi OpenGLers,
I need to have uninterrupted display (with no drop) of frames for a psychophysical experiment. For that purpose, I need to spawn a thread dedicated to the display (and redisplay) of my screen. I know how to set the policy of and create and parameterize a new thread. My OpenGL code is also up and running (when I do not use multithreading). Can someone help me tell me (or preferrably give me an outline code) for how to make my OpenGL display function a thread.

I have tried to pass the pointer to my thread to the glutDisplayFunc() and glutIdleFunc(). It works but there are some minor problems (e.g. the program instead of going to the glutMainLoop(), exits after the first round of display.

Here is a simplified version of my main()

int main(int argc, char **argv)
{
pthread_t p_th;
pthread_attr_t pth_att;
int status;

if ( (status=pthread_attr_init(&pth_att)) != 0 )
exit(1);
if ( (status=pthread_attr_setdetachstate(&pth_att, PTHREAD_CREATE_DETACHED)) != 0 )
exit(2);
if ( (status=pthread_create(&p_th, &pth_att, pth_main, NULL)) != 0 )
exit(3);

glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE);
glutInitWindowSize(1024, 768);
glutInitWindowPosition(0, 0);
window = glutCreateWindow("bla bla bla");

InitGL();
glutDisplayFunc(&pth_main);
glutIdleFunc(&pth_main);
glutMainLoop();
return 1;
pthread_exit(NULL);
}

Thanks for any help.

Mehrdad

jwatte
01-10-2003, 07:08 PM
Glut is not compatible with threading.

If you think that you can use Windows, or MacOS X, or plain Linux, for real-time uses, please note that neither of these OSes can guarantee real-time responses better than a few dozen milliseconds under stress conditions.

Robbo
01-11-2003, 12:37 AM
Yea - you won't guarantee processor time with your thread - only that it will have more time than thread of lower priority and probably less time than system level code!

What are you trying to do exactly? If you don't want to drop any frames then make sure you draw\swap all of the frames - if you don't want to drop any frames AND you want a steady framerate, heres the deal:

You want to make sure you have a fast enough gfx card and processor to render your scene within the framerate bounds you set (with some to spare) - then you can hang your rendering code on a simple timer.

remedios79
01-11-2003, 10:00 AM
Hi, I'm using glut and GLUI windows and multithreading.
Basicly I'm calculating an isosurface (a list of triangles) and I display the list during its construction.
What do you mean when you say that glut is not compatible with multithreading?

I have some strange problems... sometimes the program crashes without any reason and the crash is in the instruction push_back (I'm using STL).

Any idea about what kind of problem I could have?

Thank you,
Remedios

jwatte
01-11-2003, 10:04 AM
The STL is also not multi-thread safe. The spec is silent on the matter, and all implementations I've seen don't do locking. You have to serialize all access to containers yourself. If you don't, you'll race and crash.

Threads really are quite a "power" tool, and if you don't take good care when using them, you'll cut yourself pretty badly.

remedios79
01-11-2003, 10:11 AM
Really?

I'm finding thousands of problems in STL... gosh...

Ok, but I'm simply adding a new object to a vector with push_back, and displaying the current list of objects (triangles).

How can I lock the vector during displaying?
Thank you,
Remedios

LordOfTheUniverse
01-11-2003, 11:48 AM
GLFW is multithread - safe
(i hope)

jwatte
01-11-2003, 12:40 PM
Remedios,

If you don't know what synchronization primitives are available for yor platform, I suggest you take some basic threading tutorials and maybe read up a little bit on some reference material about threading and synchronization. Or, perhaps better, just give up on the threading idea.

On Windows, use a CRITICAL_SECTION. On Linux, use a pthread_mutex.

remedios79
01-11-2003, 01:16 PM
Thank you for the help.
I know how to use multithreading, but thanks to a dumb professor I never used them in practice before (only pseudocode).

I know how to use mutex, but I wonder why I need it... in fact my displaying procedure do this:

for (int i = 0; i < (int)triangles.size(); ++i)
displayTriangle(triangles[i]);

and in the calculating procedure I create a new triangle, and then I push it in the vector with push_back.

So: where is the problem? The value of triangle.size() is checked run-time, and however the only problem I can have is that the last triangles are not displayed... isn't it?

Can you explain me why I need to use a mutex?

Thank you again,
Remedios

roffe
01-11-2003, 03:46 PM
Can you explain me why I need to use a mutex?


I don't know how the push_back funtion is implemented, but if the size of the vector was updated before that extra triangle was added, by push_back, you might have a problem. I don't think it is implemented like that though, but it is something you shouldn't have to worry about . That is why you need the mutex.

mjaz
01-12-2003, 06:25 AM
The Kernel programming docunmentation from Apple claims that in OS X, real-time multithreading is possible (and I know of people who have successfully tamed the beast). It however, seems to need access to 'mach' API sitting under the POSIX. The iTunes software, for instance, uses multithreading in a real-time fashion by guaranteeing a fraction of CPU time to playing music.
What I need is to make sure that on every refresh time of my monitor, I get the new frame and not drop any frames. The problem that I am having is that in an hour experiment, occasionally, the OS X decides to do some other things (house keeping and etc.) which prolong the calculations I need to do to make the new frame and therefore, a frame gets dropped.
Now what I need is not absolute real-time; I only need a garaunteed fraction of CPU time to my OpenGL drawing function between consecutive refreshes.
Now some of you say that GLUT does not support multithreading. I know of other labs that are using Cocoa with the openGL API to do what is very similar but I do not know how.
If you are familiar with OS X and Cocoa, can you please tell me if you have used multithreading (or at least two threads, one for the main function and one for the openGL drawing).

Thanks in advance,

Mehrdad

jwatte
01-12-2003, 07:12 AM
If you only currently have one thread in your program, then you don't actually need a mutex, and your crashing in push_back() is because of something else.

If the place that puts triangles in the vector is in another thread than the place that draws the vector, you will need to serialize access to the vector, by putting a mutex around both those places (the SAME mutex :-)

If you crash in push_back when your program is single-threaded, then you're either passing bad data into push_back(), or you've corrupted memory by writing through a bad pointer. Stepping through your code in the debugger, and analyzing the call stack at the point of the crash, ought to lead you to that.

remedios79
01-12-2003, 10:03 AM
The second option was right (and I put the SAME mutex! http://www.opengl.org/discussion_boards/ubb/smile.gif

Of course, the push_back function can't be atomic...

Now it works! Thank you all!

Remedios

marcus256
01-12-2003, 10:20 PM
Originally posted by LordOfTheUniverse:
GLFW is multithread - safe
(i hope)

Sorry to disappoint you http://www.opengl.org/discussion_boards/ubb/frown.gif GLFW is NOT 100% thread safe. I want to get there, but presently it isn't. This is explained in section 8 of the GLFW Users Guide (I should probably put this in the FAQ too).

I think the proper way to do multi threaded OpenGL apps is to confine all OpenGL rendering etc to one thread, but dispatch computationally heavy work etc to separate threads - at least if your goal is to make your app more responsive on SMP/SMT systems.

Tasks that do not need to be hard synced with the display can also be put in separate threads (e.g. sound, I/O etc).

(BTW, the GLFW Users Guide has a - quite comprehensive - introduction to threading)


[This message has been edited by marcus256 (edited 01-13-2003).]

marcus256
01-12-2003, 10:30 PM
Originally posted by remedios79:
Of course, the push_back function can't be atomic...

That is the point. Actually, you should NEVER make any assumptions about a function being atomic or not. Even the simplest function (e.g. i++) might look atomic, but once the code is compiled and executes, it isn't. Most operations are load-modify-store, and most load-modify-store operationas are NOT atomic.

I even think that some assembler instructions can be non-atomic (??). In any case, code that can be atomic on one architecture may not be atomic on another architecture... ALWAYS use mutexes for shared data!

Xiaofeng
01-12-2003, 11:32 PM
Originally posted by marcus256:
I think the proper way to do multi threaded OpenGL apps is to confine all OpenGL rendering etc to one thread, but dispatch computationally heavy work etc to separate threads - at least if your goal is to make your app more responsive on SMP/SMT systems

hi, Is it safe to build a set of display lists in one thread and call the lists in another thread? For example:

Thread one:
while(GetDisplayData(&pData))
{ ...
GLuint list = GLBuildDisplayList(pData);
MutexPut(list, queue);
...
}

Thread another:
while(MutexGet(&list, queue))
{ ...
glCallList(list);
...
}

thank you!

[This message has been edited by Xiaofeng (edited 01-13-2003).]

marcus256
01-13-2003, 02:54 AM
Originally posted by Xiaofeng:
hi, Is it safe to build a set of display lists in one thread and call the lists in another thread? For example:


I believe that this can be difficult (at least it may not do what you want). Each thread has its own rendering context, but only one thread can work with a specific context at a time. Quote MSDN:

"A rendering context can be current to only one thread at a time. You cannot make a rendering context current to multiple threads."

Hmmm.... Come to think of it, you probably can solve this by creating two different context (one for each thread), and share the display lists between the two contexts (e.g. using wglShareLists or the shareList argument to glXCreateContext).

In any case you need to use mutexes (and condition variables) to serialize the access to the display lists (which seems to be what you did in your examples).

gaby
01-13-2003, 05:51 AM
My idea might be crappy : but, use Mac OS 9 - this OS is not multi threaded, so, if you get the hand without calling "GetNextEvent" (or the event manager), you will run ONLY in your thread without switching !!!

Gaby

marcus256
01-13-2003, 09:38 AM
My idea might be crappy

Yes http://www.opengl.org/discussion_boards/ubb/wink.gif


use Mac OS 9 - this OS is not multi threaded

I think it is, actually. Check Apple TN2028 (http://developer.apple.com/technotes/tn/tn2028.html) .


so, if you get the hand without calling "GetNextEvent" (or the event manager), you will run ONLY in your thread without switching !!!

Well, the point here is that you WANT to switch, in order to utilize multiple threads and possibly multiple CPUs (if I didn't miss the point of the discussion at hand completely). Using mutexes etc is just a way to do it in a secure way.

Single threading is always "safe", but that can be done in any environment - even a multi threaded one (you explicitly ask for a thread to be created - it's not something magical that happens out of control).

jwatte
01-13-2003, 02:02 PM
{quote]
Single threading is always "safe", but that can be done in any environment - even a multi threaded one (you explicitly ask for a thread to be created - it's not something magical that happens out of control).
[/QUOTE]

Except, of course, for BeOS (R.I.P.)

V-man
01-13-2003, 08:25 PM
Originally posted by marcus256:
Quote MSDN:

"A rendering context can be current to only one thread at a time. You cannot make a rendering context current to multiple threads."


It might be possible to copy the rendering context from one thread to the other.
By definition, "being current" would mean that all you have to do is make sure that you don't make the same RC be current (wglMakeCurrent) in both threads.

It might work, but I have never done this.