Warning: this page refers to an old version of SFML. Click here to switch to the latest version.

Using threads and mutexes

Introduction

First, I must say that this tutorial is not the most important one. In fact you can start learning and using SFML without threads and mutexes. But as the system package is the base for every other package, it is important to know what features it can provide you.

What is a thread ?

First, what is a thread ? What should you use it for ?

Basically, a thread is a way to run a set of instructions independently of the main thread (every program runs in a thread : it is a monothreaded program ; when you add one or more threads, it is called a multithreaded program). It is just like running another process, except that it is much lighter -- threads are also called lightweight processes. All threads share the same datas as their parent process. As a result, you can have two or more sets of instructions running in parallel within your program.
Ok, so when should you use threads ? Basically, when you have to run something that would take long (complex calculations, waiting for something, ...), and you still want to do something else at the same time. For example, you may want to be able to display a graphical interface while you load your game resources (that takes usually a long time), so you can put all the loading code into a separate thread. It is also widely used in network programming, to wait for network data to be received while continuing running the program.

In SFML, threads is defined by the sf::Thread class. There are two ways of using it, depending on your needs.

Using sf::Thread with a callback function

The first way of using sf::Thread is to provide it a function to run. When you start the thread, the provided function will be called as the entry point of the thread. The thread will finish automatically when the function reaches its end.

Here is a simple example :

#include <SFML/System.hpp>
#include <iostream>

void ThreadFunction(void* UserData)
{
    // Print something...
    for (int i = 0; i < 10; ++i)
        std::cout << "I'm the thread number 1" << std::endl;
}

int main()
{
    // Create a thread with our function
    sf::Thread Thread(&ThreadFunction);

    // Start it !
    Thread.Launch();

    // Print something...
    for (int i = 0; i < 10; ++i)
        std::cout << "I'm the main thread" << std::endl;

    return EXIT_SUCCESS;
}

When Thread.Launch() is called, the execution is split into two parallel flows, meaning that ThreadFunction() will execute while main() is finishing. So the text from both threads will be displayed at the same time.

Be careful : here the main() function can finish before ThreadFunction(), ending the program while the thread is still running. However this is not the case : the destructor of sf::Thread will wait for the thread to finish, to make sure the internal thread doesn't live longer than the sf::Thread instance that owns it.

If you have some datas to pass to the thread function, you can pass it to the sf::Thread constructor :

MyClass Object;
sf::Thread Thread(&ThreadFunction, &Object);

You can then get it back with the UserData parameter :

void ThreadFunction(void* UserData)
{
    // Cast the parameter back to its real type
    MyClass* Object = static_cast<MyClass*>(UserData);
}

Make sure the data you pass is valid as long as the thread function needs it !

Using sf::Thread as a base class

Using a callback function as a thread is easy, and can be useful in some cases, but is not very flexible. What if you want to use a thread in a class ? What if you have to share more variables between your thread and the main one ?

To allow more flexibility, sf::Thread can also be used as a base class. Instead of passing it a callback function to call, just inherit from it and override the virtual function Run(). Here is the same example as above, written with a derived class instead of a callback function :

#include <SFML/System.hpp>
#include <iostream>

class MyThread : public sf::Thread
{
private :

    virtual void Run()
    {
        // Print something...
        for (int i = 0; i < 10; ++i)
            std::cout << "I'm the thread number 2" << std::endl;
    }
};

int main()
{
    // Create an instance of our custom thread class
    MyThread Thread;

    // Start it !
    Thread.Launch();

    // Print something...
    for (int i = 0; i < 10; ++i)
        std::cout << "I'm the main thread" << std::endl;

    return EXIT_SUCCESS;
}

If running a separate thread is an internal feature that doesn't need to appear in your class' public interface, you can use private inheritance :

class MyClass : private sf::Thread
{
public :

    void DoSomething()
    {
        Launch();
    }

private :

    virtual void Run()
    {
        // Do something...
    }
};

As a result, your class won't expose all the thread-related functions in its public interface.

Terminating a thread

As we already said, a thread is terminated when is associated function ends. But what if you want to end a thread from another thread, without waiting for its function to end ?

There are two ways of terminating a thread, but only one is really safe to use. Let's first have a look at the unsafe way to terminate a thread :

#include <SFML/System.hpp>

void ThreadFunction(void* UserData)
{
    // Do something...
}

int main()
{
    // Create a thread with our function
    sf::Thread Thread(&ThreadFunction);

    // Start it !
    Thread.Launch();

    // For some reason, we want to terminate the thread
    Thread.Terminate();

    return EXIT_SUCCESS;
}

By calling Terminate(), the thread will be immediatly killed with no chance to finish its execution properly. It's even worse, because depending on your operating system, the thread may not cleanup the resources it uses.
Here is what MSDN says about the TerminateThread function for Windows : TerminateThread is a dangerous function that should only be used in the most extreme cases.

The only way to safely terminate a running thread is simply to wait for it to finish by itself. To wait for a thread, you can use its Wait() function :

Thread.Wait();

So, to tell a thread to terminate, you can send it en event, set a boolean variable, or whatever. And then wait until it finishes by itself. Here is an example :

#include <SFML/System.hpp>

bool ThreadRunning;

void ThreadFunction(void* UserData)
{
    ThreadRunning = true;
    while (ThreadRunning)
    {
        // Do something...
    }
}

int main()
{
    // Create a thread with our function
    sf::Thread Thread(&ThreadFunction);

    // Start it !
    Thread.Launch();

    // For some reason, we want to terminate the thread
    ThreadRunning = false;
    Thread.Wait();

    return EXIT_SUCCESS;
}

This is easy, and much safer than calling Terminate().

Pausing a thread

You can pause the main thread or a thread that you've created, with the sf::Sleep function :

sf::Sleep(0.1f);

As every duration in SFML, the parameter is a floating value defining the pause duration in seconds. Here the thread will sleep for 100 ms.

Using a mutex

Ok, let's first quickly define what a mutex is. A mutex (which stands for MUTual EXclusion) is a synchronization primitive. It is not the only one : there are semaphores, critical sections, conditions, etc. But the most useful one is the mutex. Basically, you use it to lock a specific set of instructions that cannot be interrupted, to prevent other threads from accessing it. While a mutex is locked, any other thread trying to lock it will be paused until the owner thread unlocks the mutex. Typically it is used to access a variable shared between two or more threads.

If you run the examples above, you will see that the output is maybe not what you expected : texts from both threads are blended together. This is because the threads are accessing the same resource at the same time (in this case, the standard output). To avoid this, we can use a sf::Mutex :

#include <SFML/System.hpp>
#include <iostream>

sf::Mutex GlobalMutex; // This mutex will be used to synchronize our threads

class MyThread : public sf::Thread
{
private :

    virtual void Run()
    {
        // Lock the mutex, to make sure no thread will interrupt us while we are displaying text
        GlobalMutex.Lock();

        // Print something...
        for (int i = 0; i < 10; ++i)
            std::cout << "I'm the thread number 2" << std::endl;

        // Unlock the mutex
        GlobalMutex.Unlock();
    }
};

int main()
{
    // Create an instance of our custom thread class
    MyThread Thread;

    // Start it !
    Thread.Launch();

    // Lock the mutex, to make sure no thread will interrupt us while we are displaying text
    GlobalMutex.Lock();

    // Print something...
    for (int i = 0; i < 10; ++i)
        std::cout << "I'm the main thread" << std::endl;

    // Unlock the mutex
    GlobalMutex.Unlock();

    return EXIT_SUCCESS;
}

If you wonder why we don't use a mutex to access the ThreadRunning shared variable in the example above (about thread termination), here are the two reasons :

Be careful when using a mutex or any other synchronization primitive : if not used with caution, they can lead to deadlocks (two or more locked threads waiting for each other indefinitely).

But there is still one problem : what happens if an exception is thrown while a mutex is locked ? The thread will never have a chance to unlock it, probably causing a deadlock and freezing your program. To handle this without having to write tons of extra code, SFML provides a sf::Lock.

A safer version of the example above would be :

{
    // Lock the mutex, to make sure no thread will interrupt us while we are displaying text
    sf::Lock Lock(GlobalMutex);

    // Print something...
    for (int i = 0; i < 10; ++i)
        std::cout << "I'm the main thread" << std::endl;

}// The mutex is unlocked automatically when the sf::Lock object is destroyed

The mutex is unlocked in the sf::Lock destructor, which will be called even if an exception is thrown.

Conclusion

Threads and mutexes are easy to use, but be careful : parallel programming can be a lot harder than it seems. Avoid threads if you don't really need them, and try to share as few as possible variables between them.

You can now go back to the tutorials index, or jump to the tutorials about the windowing package.