title: C++11 + SDL2 + Windows: Multithreaded program hangs after any input event
body: <p>I am working on a screen capture program using C++11, MinGW, and the Windows API.  I am trying to use SDL2 to watch how my screen capture program works in real time.</p>
  
  <p>The window opens fine, and the program seems to run well so long as I do nothing more than move the mouse cursor.  But iff I click in the window, its menu bar, outside the window, or press any keys, the SDL window freezes.</p>
  
  <p>I have set up some logging for the events to figure out what is happening.  I never receive any events other than <code>SDL_WINDOW_FOCUS_GAINED</code>, <code>SDL_TEXTEDITING</code>, and <code>SDL_WINDOWEVENT_SHOWN</code> in that order.  All of these are received at the start.</p>
  
  <p>I have tried to find tutorials on SDL event handling since that's my best guess as to the source of the problem.  I have found nothing more than basic event handling to watch for <code>SDL_QUIT</code>, basic mouse and keyboard events, and one on <code>SDL_WINDOWEVENT</code>s that does not seem to help.  I have found nothing in-depth on what the events mean and best practices for handling them.  That may not matter, because that might not be the source of the problem.  For all I know, SDL is throwing a fit because there are other threads running.</p>
  
  <p><strong>Can anyone see any cause for this hanging in my code and provide an explanation as to how to fix it?</strong></p>
  
  <p>A quick explanation for the structure of my program is in order to cover the code I have omitted.  The <code>Captor</code> class starts and runs a thread to grab a screenshot to pass to the <code>Encoder</code>.  The <code>Encoder</code> starts a variable number of threads that receive a screenshot from the <code>Captor</code>, encode the screenshot, then passes the encoding to the <code>Screen</code>.  The passing mechanism is the <code>SynchronousQueue&lt;T&gt;</code> class that provides paired methods <code>put(const T&amp;)</code> and <code>T get()</code> to allow a producer and a consumer to synchronize using a resource; these methods time out to allow the the system to be responsive to kill messages.</p>
  
  <p>Now for the source files (hopefully without too much bloat).  <em>While I would appreciate any comments on how to improve the performance of the application, my focus is on making the program responsive.</em></p>
  
  <p><strong>main.cpp</strong></p>
  
  <pre><code>#include "RTSC.hpp"
  
  int main(int argc, char** argv) {
      RTSC rtsc {
          (uint32_t) stoi(argv[1]),
          (uint32_t) stoi(argv[2]),
          (uint32_t) stoi(argv[3]),
          (uint32_t) stoi(argv[4]),
          (uint32_t) stoi(argv[5]),
          (uint32_t) stoi(argv[6])
      };
  
      while (rtsc.isRunning()) {
          SwitchToThread();
      }
  
      return 0;
  }
  </code></pre>
  
  <p><strong>RTSC.hpp</strong></p>
  
  <pre><code>#ifndef RTSC_HPP
  #define RTSC_HPP
  
  #include "Captor.hpp"
  #include "Encoder.hpp"
  #include "Screen.hpp"
  
  #include &lt;iostream&gt;
  using namespace std;
  
  
  class RTSC {
      private:
          Captor *captor;
          Encoder *encoder;
  
          SynchronousQueue&lt;uint8_t*&gt; imageQueue {1};
          SynchronousQueue&lt;RegionList&gt; regionQueue {1};
  
          Screen *screen;
  
      public:
          RTSC(
              uint32_t width,
              uint32_t height,
              uint32_t maxRegionCount,
              uint32_t threadCount,
              uint32_t divisionsAlongThreadWidth,
              uint32_t divisionsAlongThreadHeight
          ) {
              captor = new Captor(width, height, imageQueue);
              encoder = new Encoder(
                  width,
                  height,
                  maxRegionCount,
                  threadCount,
                  divisionsAlongThreadWidth,
                  divisionsAlongThreadHeight,
                  imageQueue,
                  regionQueue
              );
  
              screen = new Screen(
                  width,
                  height,
                  width &gt;&gt; 1,
                  height &gt;&gt; 1,
                  regionQueue
              );
  
              captor-&gt;start();
          }
  
          ~RTSC() {
              delete screen;
              delete encoder;
              delete captor;
          }
  
          bool isRunning() const {
              return screen-&gt;isRunning();
          }
  };
  
  #endif
  </code></pre>
  
  <p><strong>Screen.hpp</strong></p>
  
  <pre><code>#ifndef SCREEN_HPP
  #define SCREEN_HPP
  
  #include &lt;atomic&gt;
  #include &lt;SDL.h&gt;
  #include &lt;windows.h&gt;
  
  #include "Region.hpp"
  #include "SynchronousQueue.hpp"
  
  using namespace std;
  
  class Screen {
      private:
          atomic_bool running {false};
          HANDLE thread;
          SynchronousQueue&lt;RegionList&gt;* inputQueue;
          uint32_t inputHeight;
          uint32_t inputWidth;
          uint32_t screenHeight;
          uint32_t screenWidth;
  
          SDL_Renderer* renderer;
          SDL_Surface* surface;
          SDL_Texture* texture;
          SDL_Window* window;
  
          void run() {
              SDL_Event event;
              while (running) {
                  while (SDL_PollEvent(&amp;event)) {
                      switch (event.type) {
                          case SDL_QUIT:
                              running = false;
                              break;
  
                          case SDL_WINDOWEVENT:
                              switch (event.window.event) {
                                  case SDL_WINDOWEVENT_CLOSE:
                                      running = false;
                                      break;
  
                          default:
                              break;
                      }
                  }
  
                  try {
                      RegionList rl = inputQueue-&gt;get();
  
                      SDL_RenderClear(renderer);
  
                      SDL_LockSurface(surface);
                      SDL_FillRect(surface, nullptr, 0);
  
                      for (uint32_t i = 0; i &lt; rl.count; ++i) {
                          Region &amp;r = rl.regions[i];
  
                          SDL_Rect rect {
                              (int) r.getX(),
                              (int) r.getY(),
                              (int) r.getWidth(),
                              (int) r.getHeight()
                          };
                          uint32_t color =
                              (r.getRed() &lt;&lt; 16) +
                              (r.getGreen() &lt;&lt; 8) +
                              r.getBlue();
                          SDL_FillRect(surface, &amp;rect, color);
                      }
  
                      SDL_UnlockSurface(surface);
                      SDL_UpdateTexture(
                          texture,
                          nullptr,
                          surface-&gt;pixels,
                          surface-&gt;pitch
                      );
                      SDL_RenderCopyEx(
                          renderer,
                          texture,
                          nullptr,
                          nullptr,
                          0,
                          nullptr,
                          SDL_FLIP_VERTICAL
                      );
                  } catch (exception &amp;e) {}
  
                  SDL_RenderPresent(renderer);
                  SwitchToThread();
              }
          }
  
          static DWORD startThread(LPVOID self) {
              ((Screen*) self)-&gt;run();
              return (DWORD) 0;
          }
  
      public:
          Screen(
              uint32_t inputWidth,
              uint32_t inputHeight,
              uint32_t windowWidth,
              uint32_t windowHeight,
              SynchronousQueue&lt;RegionList&gt; &amp;inputQueue
          ): inputQueue {&amp;inputQueue}, inputHeight {inputHeight} {
              SDL_Init(SDL_INIT_VIDEO);
  
              window = SDL_CreateWindow(
                  "RTSC",
                  SDL_WINDOWPOS_CENTERED,
                  SDL_WINDOWPOS_CENTERED,
                  windowWidth,
                  windowHeight,
                  SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE |
                      SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS
              );
  
              renderer = SDL_CreateRenderer(window, -1, 0);
  
              surface = SDL_CreateRGBSurface(
                  0,
                  inputWidth,
                  inputHeight,
                  24,
                  0xFF &lt;&lt; 16,
                  0xFF &lt;&lt; 8,
                  0xFF,
                  0
              );
  
              texture = SDL_CreateTexture(
                  renderer,
                  surface-&gt;format-&gt;format,
                  SDL_TEXTUREACCESS_STREAMING,
                  inputWidth,
                  inputHeight
              );
  
              running = true;
              thread = CreateThread(nullptr, 0, startThread, this, 0, nullptr);
          }
  
          ~Screen() {
              running = false;
              WaitForSingleObject(thread, INFINITE);
              CloseHandle(thread);
  
              SDL_FreeSurface(surface);
              SDL_DestroyRenderer(renderer);
              SDL_DestroyWindow(window);
              SDL_Quit();
          }
  
          bool isRunning() const {
              return running;
          }
  };
  
  #endif
  </code></pre>