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