これで完璧?
pushに失敗するのが笑えるけど実際には
OSのタイムスライスはpush/popより十分大きいから最悪のケースは発生しなさそうだ。

volatile bool entering_push;
volatile bool entering_pop;

bool push()
{
 entering_push = true;
 if(entering_pop && size() < 2)
  return false;
 ...
 entering_push = false;
}

void *pop()
{
 entering_pop = true;
 if(entering_push && size() < 3)
  return 0;
 ...
 entering_pop = false;
}