Aug 13 2008

Multithreaded Task System Arguments

Published by mdanks at 10:08 pm under Code, Games

I have implemented a task system for my brushing program. In many ways, it emulates a PS3 by creating 6 threads which sleep until told to do something. That “something” is a function which does a task and then exits. There are two issues with this that I am resolving at the moment.

  1. It is hard to debug the tasks when there are hundreds or thousands a frame
  2. I want to emulate the PS3 SPU local store, which means segmenting my memory space

To make each of these easier to deal with, all of the task entry functions take an argument. This argument is a pointer to a ClTaskArg class. Tasks are expected to derive from this class to get their arguments into, and potentially out of, the task function.

Here is the basic flow chart for how a task gets executed in my app.

The decision points are mainly decided by the settings in the argument. This is different from how most PC or XBox360 apps would work, since they have unified memory. By creating a Local Store for the Task Function, it forces the app to think about how memory is handled and when to actually do a writeback. The nice thing about my system is that a fair amount of the memory handling is done automatically without having to explicitly do the memcpy() in the user’s code.

A simplified and incomplete version of my ClTaskArg follows. It mimics the PS3 by using EA – Effective Address. The implementation is missing, as well as a lot of the header itself, but it should give an idea of how I deal with the argument into the Task Entry Function.

class ClTaskArg
{
    public :

        //////////
        // Get the size of this structure
        int            getSizeOfStruct() const    { return(mcSizeOfStruct); }

        //////////
        // Get the write back address
        // [out] ClTaskArg * - the pointer in main RAM.  NULL if no write back
        ClTaskArg      *getThisEA() const         { return(mpThisEA); }

        //////////
        bool           breakOnEntry() const       { return(mBreakOnEntry); }

        //////////
        ClAlloc        *getLocalAllocator()       { return(mpLocalAlloc); }

    protected :

        //////////
        // Constructor
        // [in] sizeOfStruct - the full size of the structure to transfer
        // [in] writeBackStruct
        //        - should the structure be written back to main RAM on exit?
        ClTaskArg(int sizeOfStruct, bool writeBackStruct)
            : mpThisEA(0), mcSizeOfStruct(sizeOfStruct), mBreakOnEntry(false)
        {
            if (writeBackStruct)
            {
                mpThisEA = this;
            }
        }

    private :

        // Address of this structure in main RAM
        ClTaskArg    *mpThisEA;
        // The memory allocator for this core
        ClAlloc      *mpLocalAlloc;
        // The size of the structure
        const int    mcSizeOfStruct;
        // Should the thread break on entry?
        bool         mBreakOnEntry;
};

No responses yet

Trackback URI | Comments RSS

Leave a Reply

You must be logged in to post a comment.