# Is it thread-safe to render inside event watcher?

**URL:** <https://discourse.libsdl.org/t/is-it-thread-safe-to-render-inside-event-watcher/49409>\
**Category:** SDL Development\
**Created:** [February 24, 2024, 3:48pm UTC](https://discourse.libsdl.org/t/is-it-thread-safe-to-render-inside-event-watcher/49409 "2024-02-24T15:48:27Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Peter87](https://discourse.libsdl.org/letter_avatar_proxy/v4/letter/p/f07891/32.png) [@Peter87](https://discourse.libsdl.org/u/Peter87)\
**Post date:** [February 24, 2024, 3:48pm UTC](https://discourse.libsdl.org/t/is-it-thread-safe-to-render-inside-event-watcher/49409/1 "2024-02-24T15:48:27Z")

</div>

Hello everyone!

I have read the github discussion about [the main thread being blocked while moving or resizing the window](https://github.com/libsdl-org/SDL/issues/1059) on some platforms. If I understand correctly this will not be an issue in SDL3 if you use the [main callbacks](https://wiki.libsdl.org/SDL3/README/main-functions#how-to-use-main-callbacks-in-sdl3).

My question is about the proposed workaround when using the traditional approach where `SDL_PollEvent` is called manually (which is the only option in SDL2).

> [slouken wrote:](https://github.com/libsdl-org/SDL/issues/1059#issuecomment-1802723797)  
> I’ve added a solution that dovetails nicely with the new main callbacks in SDL 3.0 and **if you’re not using that you can set an event watcher to handle expose events and draw then**.

There is also an [example](https://github.com/libsdl-org/SDL/blob/SDL2/test/testsprite2.c) that uses this approach. It uses `SDL_AddEventWatch` to register a callback that ends up calling a bunch of render functions (including `SDL_RenderPresent`).

The wiki page for [SDL\_RenderPresent](https://wiki.libsdl.org/SDL2/SDL_RenderPresent) says:

> “You may only call this function on the main thread.”

The wiki page for [SDL\_AddEventWatch](https://wiki.libsdl.org/SDL2/SDL_AddEventWatch) says:

> “WARNING: Be very careful of what you do in the event filter function, as it may run in a different thread!”

Am I missing something, is there perhaps an undocumented guarantee that the event watcher will always be invoked on the main thread when dealing with window events, or is this simply not thread-safe?

---

<div class="post-metadata">

**Author:** ![slouken](https://discourse.libsdl.org/letter_avatar_proxy/v4/letter/s/ec9cab/32.png) [@slouken](https://discourse.libsdl.org/u/slouken)\
**Post date:** [February 25, 2024, 3:59am UTC](https://discourse.libsdl.org/t/is-it-thread-safe-to-render-inside-event-watcher/49409/2 "2024-02-25T03:59:14Z")

</div>

That particular event will only happen on the main thread, so it’s safe to render in response to that event. Other events may happen on other threads, so it’s not safe in general to render from an event callback.

---

<div class="post-metadata">

**Author:** ![Peter87](https://discourse.libsdl.org/letter_avatar_proxy/v4/letter/p/f07891/32.png) [@Peter87](https://discourse.libsdl.org/u/Peter87)\
**Post date:** [February 25, 2024, 8:07am UTC](https://discourse.libsdl.org/t/is-it-thread-safe-to-render-inside-event-watcher/49409/3 "2024-02-25T08:07:01Z")

</div>

Thank you for the clarification.

---

<div class="post-metadata">

**Author:** ![flowCRANE](https://discourse.libsdl.org/user_avatar/discourse.libsdl.org/flowcrane/32/5726_2.png) [@flowCRANE](https://discourse.libsdl.org/u/flowCRANE)\
**Post date:** [February 25, 2024, 11:05am UTC](https://discourse.libsdl.org/t/is-it-thread-safe-to-render-inside-event-watcher/49409/4 "2024-02-25T11:05:13Z")

</div>

> [@slouken](#):
>
> That particular event will only happen on the main thread, so it’s safe to render in response to that event.

Is somewhere a list of events that can only happen in the main thread?

One reason why window rendering may be done in an event watcher is because the window is repainted as it stretches. One of the solutions is the `SDL_WINDOWEVENT_RESIZED` event watcher and rerendering of the window content from a callback ([example](https://stackoverflow.com/a/76743532/19103115)). Even though this works properly, it is difficult to know whether it is completely safe.

It would be useful to have a table in the documentation describing which types of events may come from which threads, what is safe and what’s not.

---

<div class="post-metadata">

**Author:** ![elefantinho](https://discourse.libsdl.org/letter_avatar_proxy/v4/letter/e/e0b2c6/32.png) [@elefantinho](https://discourse.libsdl.org/u/elefantinho)\
**Post date:** [December 27, 2024, 4:59pm UTC](https://discourse.libsdl.org/t/is-it-thread-safe-to-render-inside-event-watcher/49409/5 "2024-12-27T16:59:38Z")

</div>

> **Summary**
>
> yay I made an event filter and now I can paint my windows as it resizes on Windows!!! S2 S2
> 
> to be sure I’m on the main thread, I created a global variable called `tid`, then during startup I assign `tid = SDL_GetThreadID(NULL)`, then in every single exposure event I filter I call `SDL_assert(SDL_GetThreadID(NULL) == tid)`
> 
> regarding getting the new size during exposure… yeah, my stuff is stretching because I don’t know the new size. I can catch resize events while the resize happens, so I see I have to work inside an event filter. I see two options:
> 
> 1. use atomics, such as C11+ `_Atomic` or SDL atomic API
> 2. resize stuff as if in main thread, using `SDL_assert()` again to ensure this
> 
> now I wonder which one is more portable and robust… brb
> 
> edit: I decided to place this in my event filter:
> 
> ```C
> case SDL_WINDOWEVENT_RESIZED: // Fall through.
> case SDL_WINDOWEVENT_SIZE_CHANGED:
> if (SDL_GetThreadID(NULL) == tid)
> {
> resize(event);
> return 0;
> }
> break;
> 
> ```

I’ll keep it like this until problems arise hehe

edit: I’ve run into problems. returning zero inside event filter for resize events breaks `SDL_RenderCopy` and that is the intended consequence when returning zero. returning one makes it work, but the result is sluggish.
