digitalmars.D.learn - Shared data concurrency with SDL
- Tim Reinke (95/95) Nov 09 2013 Newbie here. I'm playing around with concurrency in D. Being
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 } }
Nov 09 2013