Orx Multithreading tutorial?

edited July 2015 in Help request
Is there a tutorial or usage guide for threading?

Comments

  • edited July 2015
    There aren't any, sorry!

    Here's a quick tour though:

    - Most of orx's API is not thread-safe, so don't try to create/delete objects from a different thread than the main one, for example, or reading config data.

    - The following APIs are thread-safe:
    - orxMemory
    - orxThread
    - all the stateless modules: orxString, orxLinkList, orxTree, orxMath, orxVector, ...
    - all the calls that do not have side effects (ie. which won't modify an internal state), such as: orxEvent_Send(), most orx*_Get*(), ...

    - orx creates a few internal threads:
    - there's a thread created in orxThread which handles all the orxThread_Run() requests
    - there's a thread in orxResource that handles all the asynchronous resource operations of read, write, close and get time
    - there's a thread in orxSoundSystem that handles the sound streaming (music), the asynchronous sound handling is done using thread tasks (orxThread_Run)

    - if you need to have a whole thread running, you should use orxThread_Start() & affiliated

    - you have semaphores for any synchronous needs: orxThread_CreateSemaphore(), orxThread_WaitSemaphore(), orxThread_SignalSemaphore() and orxThread_DeleteSemaphore()

    - if you simply want to delegate a single task, you should use orxThread_Run(). The task will be executed on the worker thread handled inside orxThread module. That's how sound and image loading/processing is handled. In addition to the thread function, you can add two optional callbacks: one which is called is the threaded function return orxSTATUS_RETURN, the other one if the function retursn orxSTATUS_FAILURE. Both those callbacks will then be called on the main thread, which is pretty important. :)

    There aren't any, sorry!

    Here's a quick tour though:

    - Most of orx's API is not thread-safe, so don't try to create/delete objects from a different thread than the main one, for example, or reading config data.

    - The following APIs are thread-safe:
    - orxMemory
    - orxThread
    - all the stateless modules: orxString, orxLinkList, orxTree, orxMath, orxVector, ...
    - all the calls that do not have side effects (ie. which won't modify an internal state), such as: orxEvent_Send(), most orx*_Get*(), ...

    - orx creates a few internal threads:
    - there's a thread created in orxThread which handles all the orxThread_RunTask() requests
    - there's a thread in orxResource that handles all the asynchronous resource operations of read, write, close and get time
    - there's a thread in orxSoundSystem that handles the sound streaming (music), the asynchronous sound handling is done using thread tasks (orxThread_RunTask)

    - if you need to have a whole thread running, you should use orxThread_Start() & affiliated

    - you have semaphores for any synchronous needs: orxThread_CreateSemaphore(), orxThread_WaitSemaphore(), orxThread_SignalSemaphore() and orxThread_DeleteSemaphore()

    - if you simply want to delegate a single task, you should use orxThread_RunTask(). The task will be executed on the worker thread handled inside orxThread module. That's how sound and image loading/processing is handled. In addition to the thread function, you can add two optional callbacks: one which is called is the threaded function return orxSTATUS_RETURN, the other one if the function returns orxSTATUS_FAILURE. Both those callbacks will then be called on the main thread, which is pretty important. :)

    - Contexts can be given to both orxThread_Start() and orxThread_RunTask().

    - Threads can be paused or resumed at will, even orx's internal ones (useful on mobile when all work should stop when an app is sent in the background or even on computer to stop any sound streaming & co). Here's an example of what I do in Little Cells, when handling system events:
    case orxSYSTEM_EVENT_BACKGROUND:
    {
      // Saves
      Cell::GetInstance().Save();
    
      // Disables all threads
      orxThread_Enable(orxTHREAD_KU32_FLAG_NONE, orxTHREAD_KU32_MASK_ALL);
    
      break;
    }
    
    case orxSYSTEM_EVENT_FOREGROUND:
    {
      // Enables all threads
      orxThread_Enable(orxTHREAD_KU32_MASK_ALL, orxTHREAD_KU32_FLAG_NONE);
    
      break;
    }
    

    - By default images will be loaded asynchronously and a placeholder (aka temp) texture will be used if an object is rendered which is using a load pending texture. That temp texture (white pixel), can be modified in code by calling orxDisplay_SetTempTexture(). If you pass orxNULL to this function (ie. no temp texture), then all the image loading calls will then be synchronous. One can thus control which texture loads should be synchronous or not by changing the temp texture at runtime if needed.

    - Sounds will always be loaded asynchronously, there's no way to have them loaded synchronously at the moment.

    - Resources are handled synchronously if you pass orxNULL as callback and asynchronously if you provide a callback

    And now here's some details about orxThread_RunTask() as it's likely what users are going to be using for most of their threading needs:

    The first parameter will be the function executed on the worker thread, it should not block too long, otherwise other tasks might be delayed. I'll extend the pool of workers in the future and probably allow users to create their own worker thread as well. The advantage of the worker thread compared to just start and handle your own thread is that some main/worker thread synchronization is done for you, as well as context handling.

    Depending on the return value of the function passed as first parameter, either the second or third one will get called, on the main thread. That means that you can easily postpone work that is not thread-safe but dependent on the work to be done with a single call to orxThread_RunTask(). Actually one can even pass orxNULL as first parameter, orx will assume its return result would then be orxSTATUS_SUCCESS and will execute the second function on the main thread.

    That means that, from some code that is executed on a thread which is not the main one (ie. inside a task or inside a custom thread), calling orxThread_RunTask(orxNULL, DoMainWork, orxNULL, orxNULL), will result in DoMainWork being called later on, on the main thread.

    If you have any specific question, don't hesitate!

    Cheers!

    PS: Nice to see you around, btw. :)
Sign In or Register to comment.