Shared data concurrency with SDL

Tim Reinke tim at mostcallmetim.com
Sat Nov 9 20:02:51 PST 2013


Newbie here.  I'm playing around with concurrency in D.  Being 
new to both, I have no idea what I'm doing and am seeking your 
guidance!

I'm using the D SDL wrapper (which is just a thin wrapper around 
the C library).

I have the following threads:
   - the main program thread; the `control & coordination` thread
   - SDL_Mixer has its own thread (which calls a callback I 
provide)
   - a thread to handle graphics

Questions I'm seeking answers to:
1) I'm doing a lot of casting to/from shared which doesn't feel 
right.  What should be I doing?  Some of this seems unavoidable, 
as in the SDL callback postMixCallback() where I'm bound by the 
SDL_mixer library to provide a specific type signature.

2) A specific instance of 1). In my main(), I declare 
GraphicsState to
be unshared.  GraphicsState just holds on to a bunch of pointers
returned by SDL initialization routines (which won't work on 
shared
pointers).  Then, in order to communicate with the graphics 
thread via
send(), I cast the address of to a shared pointer.  On the other 
end,
I receive this shared pointer then cast to an unshared pointer and
dereference.  I do this because the pointer values in 
GraphicsState
are passed pretty much exclusively to C functions which won't 
accept
shared types.  Seems awkward, no?

My code (also at http://pastebin.com/SMC2e9Bx )

// Holds data the graphics thread needs
// This is initialized in the main
// thread then sent to the graphics thread
// Cleanup is done by the main thread after
// the graphics thread exits
struct GraphicsState {
   SDL_Window* window;
   SDL_Renderer* renderer;
   SDL_Texture* texture;
   ImageSurface cairoSurface;
   ubyte* pixels;
}

// a simple ring buffer
struct RingBuffer {
   ulong pos;
   short[] buffer;
}


void main()
{
   // ...
   GraphicsState graphicsState;
   gfxInit(graphicsState);

   shared RingBuffer ringBuffer;
   ringBuffer.pos = 0;
   ringBuffer.buffer.length = audioConf.sample_f * 
audioConf.chunkSize;

   Mix_SetPostMix(&finished, cast(void*)&ringBuffer);

   Tid tid = spawn(&doGfx);
   shared GraphicsState* sharedGfx = cast(shared 
GraphicsState*)&graphicsState;
   send(tid, sharedGfx, cast(shared(RingBuffer*))&ringBuffer);
   // ...
}

extern(C) void postMixCallback(void* udata, ubyte *stream, int 
len)
{
   shared RingBuffer* buffer = cast(shared RingBuffer*)udata;
   short *samples = cast(short*)stream;

   // naive copy
   for (int i = 0; i < len / short.sizeof; i += 2)
   {
     buffer.buffer[buffer.pos] = *(samples + i);
     auto nextPos = buffer.pos + 1;
     if (nextPos == buffer.buffer.length)
     {
       nextPos = 0;
     }
     buffer.pos = nextPos;
   }
}

void doGfx(AudioConf audioConf)
{
   GraphicsState graphicsState;
   Mix_Chunk* beat;
   shared RingBuffer* ringBuffer;
   auto msg = receiveOnly!(shared(GraphicsState*), 
shared(RingBuffer*));

   graphicsState = *(cast(GraphicsState*)msg[0]);
   ringBuffer = msg[1];

   while (true) {
     // read from ring buffer
     // render
   }
}


More information about the Digitalmars-d-learn mailing list