SFML - Multithreading help

Hello my friends been a very long time since I visited the site hope you are all doing well.

Anyway on point, I am making a class that manages my SFML windows for me, rather than having to keep going through all the basic riff raff each time I want to make a 2D program. One of the things I would like to implement ( With hopefully performance increases ) is the event queue of the window being multithreaded.

The SFML code to grab the next event in the queue is:

1
2
3
4
5
sf::Event event; // Create reuseable event object
while(window.pollEvent(event)) // Keep popping next event from queue till none left
{
    // Do something with event - Was it a button press, mouse moved etc etc
}


To make this multithreaded, and make the class a bit more dynamic I've so far came up with this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void HandleEvents()
{
    static size_t thread_count = 0; // Purely for debugging purposes
    sf::Event event;
    while(window.pollEvent(event))
    {
        std::thread t(&ManagedWindow::EventHandler,this,event); // Create thread
        t.detach(); // Detach thread (S.O stated detach will clean up after itself upon process completion) 
        std::cout << "\rCreated event thread " << ++thread_count << ".";
    }
}
virtual void EventHandler(sf::Event e) // I've made this a copy of event, something tells me the event may change while OS is creating thread (Probably not) but to be safe
{
    switch(e.type)
    {
        case sf::Event::Closed: this->window.close(); break;
        default: return;
    }
    return;
}


So far the code compiles and runs fine, until I get A LOT of events to happen. I slam on the keyboard and click rapidly, move the mouse etc. After enough key bashing program freezes and Windows wants you to force close it with error code 0xC0000005 which I googled to be an access violation.

The thread_count differs each freeze, could be 200 could be 10,000. The only time it does crash is when you mass spam events.

Is this down to how I am using threads? Is it bad practice to give each event it's own thread of execution? Should I give the EventHandler it's own thread, rather than the individual events?

Should I not try to multithread these events at all?

Thanks in advance for any help on multithreading practices. If you need the full source just say, but I'm prety sure it's down to the threading.
Hi,
Should you at least try running the thread before you detach the thread?

1
2
3
4
std::thread t(&ManagedWindow::EventHandler,this,event); // Create thread

t.join();
t.detach();
Negative, joining the thread synchronises thread to caller. Blocking my program until thread compeltes. Detach allows process to run concurrently. I believe according to Stack Overflow.
Does that? :)
Yes, it does. If you are new to multithreading - http://www.cplusplus.com/reference/thread/thread/detach/

If I join before detach on my system system_error thrown immediatley on program execution.
Is this down to how I am using threads? Is it bad practice to give each event it's own thread of execution? Should I give the EventHandler it's own thread, rather than the individual events?

Should I not try to multithread these events at all?
Yes. Yes. No. Yes.

GUI events should always be handled in the thread that owns the particular widget/whatever, which is typically the main thread. In fact, all GUI operations should take place in the same thread. Having multiple threads call functions with the same object (this->window in your case) is something no GUI library that I know of supports. Generally, if a GUI library supports threads at all, creating a GUI object in a thread causes it to be bound to that thread, and using the object in any way from any other thread, even synchronously, is unsafe. Your code doesn't even bother with synchronization.
So why don't you just call the function directly?
this->ManagedWindow::EventHandler(event);

Rely more on your computer's computing power. Anything can be finished in an instant :)

If std::thread just consumes too much computer memory, consider mine as an alternative.
Thanks for the reply helios, this is my first time at multithreading a GUI program.

Can you explain why it is locking up if I spam maybe 200 events in a single second? Compared to it working flawlessly when I use the program as intended? What's happening differently? Where is the access violation exactly?

all GUI operations should take place in the same thread


Could you better define GUI operations? A lot of these events which I want to multithread are button presses and mouse clicks, for example the users presses 'W' and an enum class switches to "NORTH". The actual drawing of the window, is processed in the class Functor here:

1
2
3
4
5
6
7
8
9
10
void operator()()
{
    while(window.isOpen())
    {
        HandleEvents();
        // Update any GFX here
        window.clear(sf::Color::White);
        window.display();
    }
}


This is called from Main when the ManagedWindow object is created. All ManagedWindows are created from Main, so aren't all the GUI operations being done on a single thread, Main?


Sorry if my questions seem absurd, very new to this multithreading stuff especially with GUI.



EDIT - Here is all of the shoddy code, been trying to tackle it one step at a time, first step was event handling.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <SFML/Graphics.hpp>

#include <iostream>
#include <thread>

class ManagedWindow
{
private:
    sf::RenderWindow window;
    std::string window_title;
    int window_sizex;
    int window_sizey;
public:
    ManagedWindow(std::string title, int sx, int sy)
    : window(sf::VideoMode(sx,sy),title), window_title(title)
    , window_sizex(sx), window_sizey(sy) {}
    void operator()()
    {
        while(window.isOpen())
        {
            HandleEvents();
            // Update any GFX here
            window.clear(sf::Color::White);
            window.display();
        }
    }
    void HandleEvents()
    {
        static size_t thread_count = 0;
        sf::Event event;
        while(window.pollEvent(event))
        {
            std::thread t(&ManagedWindow::EventHandler,this,event);
            t.detach();
            std::cout << "\rCreated event thread " << ++thread_count << ".";
        }
    }
    virtual void EventHandler(sf::Event e)
    {
        switch(e.type)
        {
            case sf::Event::Closed: this->window.close(); break;
            default: return;
        }
        return;
    }
};

int main()
{
    ManagedWindow window1("Hello, world",1024,768);
    window1();
    return 0;
}
Last edited on
Can you explain why it is locking up if I spam maybe 200 events in a single second? Compared to it working flawlessly when I use the program as intended? What's happening differently? Where is the access violation exactly?


Hard to say exactly without the "real" code, but there is overhead to creating and running threads. For the code you posted here, in particular, the overhead incurred by creating/running/destroying a thread for each event is likely to be the majority of your processing time, without taking possible race conditions into account.

Did you read through the sfml tutorials?
http://www.sfml-dev.org/tutorials/2.3/graphics-draw.php#drawing-from-threads
http://www.sfml-dev.org/tutorials/2.3/window-window.php#things-to-know-about-windows
Thanks for the reply cire,

I haven't looked at the threading tutorials on the SFML, I skipped that part due to wanting to use C++ threads and not sf::Thread, silly me!

I think I need clarification on what a thread actually is. Your first link states:

The only thing to remember is to deactivate a window before using it in another thread. That's because a window (more precisely its OpenGL context) cannot be active in more than one thread at the same time.


Okay sure, but the second link states:

Events must be polled in the window's thread

.... the event loop (more precisely, the pollEvent or waitEvent function) must be called in the same thread that created the window. This means that if you want to create a dedicated thread for event handling, you'll have to make sure that the window is created in this thread too. If you really want to split things between threads, it is more convenient to keep event handling in the main thread and move the rest (rendering, physics, logic, ...) to a separate thread instead. This configuration will also be compatible with the other limitation described below.


Hang on a second... Looking back at the example code of Link 1 with sf::Thread:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void renderingThread(sf::RenderWindow* window)
{
    // the rendering loop
    while (window->isOpen())
    {
        // draw...

        // end the current frame
        window->display();
    }
}

int main()
{
    // create the window (remember: it's safer to create it in the main thread due to OS limitations)
    sf::RenderWindow window(sf::VideoMode(800, 600), "OpenGL");

    // deactivate its OpenGL context
    window.setActive(false);

    // launch the rendering thread
    sf::Thread thread(&renderingThread, &window);
    thread.launch();

    // the event/logic/whatever loop
    while (window.isOpen())
    {
        ...
    }
    return 0;
}



Tell me if I'm wrong but.. isn't window now on 2 separate threads? The Main thread and the render thread?

It states that sf::Thread automatically activates the window on launch, but what is activating it in the event loop in main?


Feel like I am missing something big here..
closed account (48T7M4Gy)
@cire says:
But, hey.. keep talking out of your ass and filling the forums with misinformation and novice code while pretending you're an expert. I'm sure you're impressing yourself.


This sort of disgraceful language, exaggeration and bullying will not be tolerated Cire. Stop it and apologise..
Um... what?

I'm sorry? I don't think I'm an expert far from it, just.. trying to learn how to use multithreading properly..


Oh..

I don't know whether he deleted a post or? He hasn't said any bad language or bullied me? He has helped me before with my questions.

I have been away for a while.. I may not be up to date.
Last edited on
closed account (48T7M4Gy)
It's directed at cire attacking another good faith contributor here mega and unfortunately the only way to deal with bullies and abusers is as you know , to expose them. He refuses to do the right thing and apologise. All cowards do the same.
I see.. I'm sorry to get involved.

I'll try and work on it some more alone, thanks for all the help.
closed account (48T7M4Gy)
Like I said his bullying and bad language has been directed at another person beyond you and I . It's intolerable as far as I am concerned when people act in good faith and are treated in such a cowardly manner. believe me I regret having to expose this disgrace but he is a notorious repeat offender. Being nice to some to cover it up and curry favor with the crowd is a well known part of the pathology. Using the report button is another. But all it does is draw attention to it.
I understand kemort, thanks for the clarification.

I'll continue with my programming, always prefered it to humans anyway. :]
closed account (48T7M4Gy)
Cheers mega. My apologies if I created the impression you were somehow at fault. Stick with people - most are good! I'm just sick of the bad one's here - they spoil a good thing for the vast majority - and you're definitely not one of them.
My apologies for getting the wrong end of the stick! I thought I was over-stepping on the beginners forum and I should move it to general so I wasn't trying to act smart or something. Got me worried there Kemort. :]

I like to think I've helped a small few who visit the site. I have tried to give exactly what I recieve, and even hope one day I can be the one with 20k posts and knows everything about everything about programming hehe.

Thank you for the kind words.
I haven't looked at the threading tutorials on the SFML, I skipped that part due to wanting to use C++ threads and not sf::Thread, silly me!

The use of std::thread is recommended over sf::Thread.
http://www.sfml-dev.org/tutorials/2.3/system-thread.php#sfml-threads-or-stdthread


Tell me if I'm wrong but.. isn't window now on 2 separate threads? The Main thread and the render thread?

It states that sf::Thread automatically activates the window on launch, but what is activating it in the event loop in main?

It is the openGL context that must be associated with the rendering thread, and that's what's being activated/deactivated.
Topic archived. No new replies allowed.