November 10, 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
  }
}