So in my project I make a Event thread to catch the sdl event and may be pass it to the main thread to rander. But sometimes I get the Segementfault. this is my test code.
#include "SDL2/SDL.h"
#include <SDL2/SDL_timer.h>
#include <iostream>
#include <thread>
using namespace std;
int main() {
SDL_Init(SDL_INIT_EVERYTHING);
bool running = true;
/* this is my event thread */
auto run = [&] {
for (; running; ) {
SDL_Event event; SDL_PollEvent(&event);
// ...
SDL_Delay(10);
}
};
thread t(run);
/* and the main is the randering thread */
for (int i = 0; i < 10; ++i) {
SDL_Window *window = SDL_CreateWindow("cycle. ",
100,
100,
600,
600,
SDL_WINDOW_SHOWN);
SDL_Renderer *screen = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
// ... do some rander ...
// may be i will get some task to rander use the blocking queue
SDL_Delay(500);
SDL_DestroyRenderer(screen);
SDL_DestroyWindow(window);
}
running = false;
t.join();
SDL_Quit();
}
Fundamentally, you should try to call SDL from a single thread. Even if you decide you need to multithread your program, you should do work in other threads and then synchronize that work to the main thread, which should use SDL to render / event-handle / etc.
Your program may be segfaulting because you're attempting to join()
a thread that already join()
-ed, so you want to at least check joinable()
before you do so.
You also need to call PollEvent in a loop, since multiple events may be queued here.
But, especially since you're using Delays, it seems like you won't need the possible performance gained by multithreading your events. I would therefore suggest something like this:
#include <SDL2/SDL.h>
#include <iostream>
#include <thread>
using namespace std;
int main() {
SDL_Init(SDL_INIT_EVERYTHING);
bool running = true;
SDL_Window *window =
SDL_CreateWindow("cycle. ", 100, 100, 600, 600, SDL_WINDOW_SHOWN);
SDL_Renderer *screen =
SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
/* and the main is the randering thread */
while (running) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
// TODO: handle events
// for example, set `running` to false when the window is closed or
// escape is pressed
// ...
}
// TODO: render here
// ...
}
SDL_DestroyRenderer(screen);
SDL_DestroyWindow(window);
SDL_Quit();
}
I'm not going to assume what you do and don't need, so here's a possible solution where you multithread the events (but you really, really, really should only use this if you absolutely need it).
This does the same as your code, except it calls PollEvent in the same thread as the rendering (the main thread), but handles the events somewhere else.
For this we use a queue of events, and a mutex to make sure it's thread-safe. I'm just putting this here for completeness' sake, and you probably (definitely) don't need this.
#include <SDL2/SDL.h>
#include <iostream>
#include <mutex>
#include <queue>
#include <thread>
using namespace std;
int main() {
SDL_Init(SDL_INIT_EVERYTHING);
bool running = true;
std::mutex eventQueueMutex;
std::queue<SDL_Event> eventQueue;
auto handleEvents = [&running, &eventQueue, &eventQueueMutex] {
while (running) {
{ // scope for unique_lock
std::unique_lock<std::mutex> lock(eventQueueMutex);
if (!eventQueue.empty()) {
auto event = eventQueue.front();
eventQueue.pop();
lock.unlock();
// TODO: handle the event here
}
} // end of scope for unique_lock
std::this_thread::sleep_for(
std::chrono::milliseconds(16)); // adjust this to your needs
}
};
std::thread eventHandlerThread = std::thread(handleEvents);
SDL_Window *window =
SDL_CreateWindow("cycle. ", 100, 100, 600, 600, SDL_WINDOW_SHOWN);
SDL_Renderer *screen =
SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
/* and the main is the randering thread */
while (running) {
SDL_Event event;
eventQueueMutex.lock();
while (SDL_PollEvent(&event)) {
eventQueue.push(event); // copy event into queue
}
eventQueueMutex.unlock();
// TODO: render here
// ...
}
if (eventHandlerThread.joinable()) {
eventHandlerThread.join();
}
SDL_DestroyRenderer(screen);
SDL_DestroyWindow(window);
SDL_Quit();
}
In both of these examples, check for my TODO
comments to see where you write your code.