SFML community forums

Help => System => Topic started by: Jalfor on December 03, 2011, 12:44:40 pm

Title: Linux Threading Issue
Post by: Jalfor on December 03, 2011, 12:44:40 pm
Just grabbed some code I've been working on from my Windows machine and loaded it onto Linux and it isn't working. The error message suggests that it is on SFML's end, not mine, though when I tried the minimal threading example from the tutorials, it worked fine.

The error message is:

Code: [Select]
[xcb] Unknown sequence number while processing queue
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
ElectroToy: ../../src/xcb_io.c:273: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed.
Aborted

Process returned 134 (0x86)   execution time : 0.232 s
Press ENTER to continue.


My code (I haven't worked on it for long yet so don't judge :p)

Code: [Select]
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <iostream>

#define WIDTH 800
#define HEIGHT 600

sf::RenderWindow App();
sf::Uint8 *pixels = new sf::Uint8[WIDTH * HEIGHT * 4];

void draw(int x, int y, int r, int g, int b)
{
    pixels[(x + WIDTH * y) * 4 + 0] = r;
    pixels[(x + WIDTH * y) * 4 + 1] = g;
    pixels[(x + WIDTH * y) * 4 + 2] = b;
    pixels[(x + WIDTH * y) * 4 + 3] = 255;
}

void display(void *UserData)
{
    sf::RenderWindow App(sf::VideoMode(WIDTH, HEIGHT, 32), "Speed Test");
    sf::Image screen(WIDTH, HEIGHT);
    sf::Sprite sprite;
    while (1)
    {
        screen.LoadFromPixels(WIDTH, HEIGHT, pixels);
        sprite.SetImage(screen);
        App.Clear();
        App.Draw(sprite);
        App.Display();
    }
}

int main()
{
    sf::RenderWindow App(sf::VideoMode(WIDTH, HEIGHT, 32), "Speed Test");
    sf::Thread graphics(&display);
    sf::Clock clock;
    const sf::Input & Input = App.GetInput();
    bool mouseX = Input.GetMouseX();
    bool mouseY = Input.GetMouseY();
    bool leftMouse = Input.IsMouseButtonDown(sf::Mouse::Left);
    bool rightMouse = Input.IsMouseButtonDown(sf::Mouse::Right);
    graphics.Launch();
    while (1)
    {
        sf::Event Event;
        while (App.GetEvent(Event))
        {
            if (Event.Type == sf::Event::Closed)
                App.Close();
        }
        if (leftMouse)
            draw(mouseX, mouseY, 255, 255, 255);
    }
}
Title: Linux Threading Issue
Post by: Laurent on December 03, 2011, 02:15:40 pm
Are you aware that:
- you have one RenderWindow in your main() function
- you have another RenderWindow in your display() function
- sf::RenderWindow App() declares a function and has nothing to do with the two other App variables?

What you want is a single RenderWindow instance, shared by the main and secondary threads, right?
Title: Linux Threading Issue
Post by: Jalfor on December 08, 2011, 05:02:44 am
Yes, that is exactly what I was trying to do but I couldn't get it working.

Could someone please help me with this?
Title: Linux Threading Issue
Post by: nitrix on December 08, 2011, 05:31:05 am
I'd personally use a Singleton, but it's arguable what is best.
Title: Linux Threading Issue
Post by: Laurent on December 08, 2011, 08:12:08 am
Don't declare a global RenderWindow.
Declare a RenderWindow local to the main() function.
Pass a pointer to it to your thread function.

That's it ;)
Title: Linux Threading Issue
Post by: Jalfor on December 08, 2011, 10:27:07 am
Oh of course...didn't think of that. Thanks a bunch
Title: Linux Threading Issue
Post by: Jalfor on December 10, 2011, 10:24:12 am
Okay, I've been trying to get this working but it...well...isn't. I've got rid of most of it because it is irrelevant to my problem though I am still working on what I posted above just so you know. The code below compiles and runs on windows with MSVC++ though says something like could not create OpenGL context for this device. On Linux with Code blocks and GCC though it won't compile at all as it is complaining about conversion from int* to sf::WindowHandle. Keep in mind, my code isn't debugged because I can't, so if you pick anything up, feel free to fix it :)

Code: [Select]
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>

#define WIDTH 800
#define HEIGHT 600

void display(void *UserData)
{
sf::RenderWindow App = (int*)UserData;
    sf::Image screen(WIDTH, HEIGHT);
    sf::Sprite sprite;
    while (1)
    {
        App.Clear();
        App.Draw(sprite);
    }
}

int main()
{
    sf::RenderWindow App(sf::VideoMode(WIDTH, HEIGHT, 32), "ElectroToy");
    sf::Thread graphics(&display, &App);
    graphics.Launch();
    while (1)
    {
App.Display();
    }
}
Title: Linux Threading Issue
Post by: Laurent on December 10, 2011, 10:34:05 am
Quote
sf::RenderWindow App = (int*)UserData;

Here you're declaring a new RenderWindow instance, trying to construct it with a pointer to a RenderWindow interpreted as a pointer to int. Doesn't make sense at all :)

Here is the correct code:
Code: [Select]
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>

#define WIDTH 800
#define HEIGHT 600

void display(void *UserData)
{
   sf::RenderWindow* App = static_cast<sf::RenderWindow*>(UserData);
    sf::Image screen(WIDTH, HEIGHT);
    sf::Sprite sprite;
    while (1)
    {
        App->Clear();
        App->Draw(sprite);
    }
}

int main()
{
    sf::RenderWindow App(sf::VideoMode(WIDTH, HEIGHT, 32), "ElectroToy");
    sf::Thread graphics(&display, &App);
    graphics.Launch();
    while (1)
    {
      App.Display();
    }
}


But your code won't work as expected. Why are you using a thread?
Title: Linux Threading Issue
Post by: Jalfor on December 10, 2011, 10:59:39 am
Firstly, I am using a thread because I plan to have the main bit of the game running in one thread, and having another one doing nothing but drawing because the drawing things to bitmaps then displaying them isn't very fast and I would rather it didn't slow the whole thing down.

Ok, so I have put the fix into the code though for reasons I cannot understand, on linux it complains about the threading with the error I posted in first post. On Windows it just doesn't display the window unless I put the function call in the main thread.

Code: [Select]

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

#define WIDTH 800
#define HEIGHT 600

sf::Uint8 *pixels = new sf::Uint8[WIDTH * HEIGHT * 4];

void draw(int x, int y, int r, int g, int b)
{
    pixels[(x + WIDTH * y) * 4 + 0] = r;
    pixels[(x + WIDTH * y) * 4 + 1] = g;
    pixels[(x + WIDTH * y) * 4 + 2] = b;
    pixels[(x + WIDTH * y) * 4 + 3] = 255;
}

void display(void *UserData)
{
    sf::RenderWindow* App = static_cast<sf::RenderWindow*>(UserData);
    sf::Image screen(WIDTH, HEIGHT);
    sf::Sprite sprite;
    while (1)
    {
        screen.LoadFromPixels(WIDTH, HEIGHT, pixels);
        sprite.SetImage(screen);
        App->Clear();
        App->Draw(sprite);
        App->Display();
    }
}

int main()
{
    sf::RenderWindow App(sf::VideoMode(WIDTH, HEIGHT, 32), "ElectroToy");
    sf::Thread graphics(&display, &App);
    sf::Clock clock;
    const sf::Input & Input = App.GetInput();
    bool mouseX = Input.GetMouseX();
    bool mouseY = Input.GetMouseY();
    bool leftMouse = Input.IsMouseButtonDown(sf::Mouse::Left);
    bool rightMouse = Input.IsMouseButtonDown(sf::Mouse::Right);
    graphics.Launch();
    while (1)
    {
        sf::Event Event;
        while (App.GetEvent(Event))
        {
            if (Event.Type == sf::Event::Closed)
                App.Close();
        }
        if (leftMouse)
            draw(mouseX, mouseY, 255, 255, 255);
    }
}
Title: Linux Threading Issue
Post by: Laurent on December 10, 2011, 11:01:43 am
You must call App.SetActive(false) before launching the graphics thread.

And you should protect your pixel data with a mutex.
Title: Linux Threading Issue
Post by: Jalfor on December 10, 2011, 11:10:42 am
That fixed the problem on Windows with MSVC++ though Linux with Code::Blocks is still giving the threading error.

Also, what is the advantage of using a mutex as display() only ever reads and main() only ever writes?
Title: Linux Threading Issue
Post by: Laurent on December 10, 2011, 11:34:06 am
Quote
Linux with Code::Blocks is still giving the threading error

Which one?

Quote
Also, what is the advantage of using a mutex as display() only ever reads and main() only ever writes?

The effects of concurrent access will probably be limited in your case, but it can still happen. You could update a pixel in the middle of its upload to the graphics card; even a single read/write operation can be interrupted since not all platforms ensure that these operations are atomic.
Title: Linux Threading Issue
Post by: Jalfor on December 10, 2011, 11:42:30 am
Quote
The effects of concurrent access will probably be limited in your case, but it can still happen. You could update a pixel in the middle of its upload to the graphics card; even a single read/write operation can be interrupted since not all platforms ensure that these operations are atomic.

Ok, I'll add it once I have this working.

As for which Linux Distro; Debian (Unstable) KDE
Title: Linux Threading Issue
Post by: Laurent on December 10, 2011, 12:06:26 pm
Quote
As for which Linux Distro; Debian (Unstable) KDE

My question was "which error", not "which Linux", sorry.
Title: Linux Threading Issue
Post by: Jalfor on December 10, 2011, 12:31:50 pm
Ah, this one:

Code: [Select]

[xcb] Unknown request in queue while dequeuing
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
ElectroToy: ../../src/xcb_io.c:178: dequeue_pending_request: Assertion `!xcb_xlib_unknown_req_in_deq' failed.
Aborted

Process returned 134 (0x86)   execution time : 0.211 s
Press ENTER to continue.
Title: Linux Threading Issue
Post by: Laurent on December 10, 2011, 12:53:07 pm
Sometimes XInitThreads() must be called to make X aware that it's running in a multi-threaded application, but it shouldn't be necessary here.
Title: Linux Threading Issue
Post by: Jalfor on December 11, 2011, 01:01:45 am
How exactly do I call XInitThreads()...I assume I need to include something though I don't have the slightest clue what, and I couldn't find it with a Google search.
Title: Linux Threading Issue
Post by: Laurent on December 11, 2011, 08:15:27 am
You must include <X11/Xlib.h> (and of course this code is for Linux only).
Title: Linux Threading Issue
Post by: Jalfor on December 13, 2011, 02:05:02 pm
Thanks :D
Title: Linux Threading Issue
Post by: Laurent on December 13, 2011, 02:07:20 pm
Did it solve your problem?
Title: Linux Threading Issue
Post by: Jalfor on February 17, 2012, 08:16:39 am
Okay, I know this reply is a little late, but it did not. I have managed to narrow down the issue a bit though.

This code gives the threading error (during run-time) described on the previous page.

Code: [Select]
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>

#define WIDTH 800
#define HEIGHT 600

void display(void *UserData)
{
   sf::RenderWindow* App = static_cast<sf::RenderWindow*>(UserData);
    sf::Image screen(WIDTH, HEIGHT);
    sf::Sprite sprite;
    while (1)
    {
        App->Clear();
        App->Draw(sprite);
    }
}

int main()
{
    sf::RenderWindow App(sf::VideoMode(WIDTH, HEIGHT, 32), "ElectroToy");
    sf::Thread graphics(&display, &App);
    graphics.Launch();
    App.SetActive();
    while (1)
        App.Display();
}


However, if you remove all statements that do anything to App other than App.SetActive(false), it works.

Code: [Select]
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>

#define WIDTH 800
#define HEIGHT 600

void display(void *UserData)
{
   sf::RenderWindow* App = static_cast<sf::RenderWindow*>(UserData);
    sf::Image screen(WIDTH, HEIGHT);
    sf::Sprite sprite;
    while (1)
    {
        App->Clear();
        App->Draw(sprite);
        App->Display();
    }
}

int main()
{
    sf::RenderWindow App(sf::VideoMode(WIDTH, HEIGHT, 32), "ElectroToy");
    sf::Thread graphics(&display, &App);
    graphics.Launch();
    App.SetActive();
    graphics.Wait();
}


Now, my main application I'm working on (which is just the above further on in development) will also simply supply this error if calls to App happen in the main function as well as another one.Though at the moment, I have got rid of all App calls from the main function into another function in the same thread. This seems to execute a random number of times (usually, somewhere around 40 times) before showing the threading error. (The threading error only shows in Debug configuration) I am still trying to narrow down the cause of this and the current code is a little too long to post on the forums but if you want to see it, I'll post it. (It's just a bit of a mess).

Thanks for any help
Title: Linux Threading Issue
Post by: Laurent on February 17, 2012, 08:42:47 am
Your first code is not supposed to work: a window can only be active in one thread at the same time. Note that calling Clear/Draw/Display implicitely tries to activate the window.

Your second code works as expected, all the graphics calls are done in the same thread. Except that SetActive() should be SetActive(false) in the main thread.
Title: Linux Threading Issue
Post by: Jalfor on February 17, 2012, 10:12:33 am
That explains everything...thanks a bunch
Title: Linux Threading Issue
Post by: Jalfor on February 17, 2012, 10:55:23 am
Actually, I think I need help on just one other small thing that isn't quite worth making a new thread about. What would the best way of getting events from the "graphics" thread into the main thread. I frankly, cannot see how to do this without tossing huge amounts of data between threads and even then, I'm not quite sure what to do.

Thanks a lot
Title: Linux Threading Issue
Post by: Laurent on February 17, 2012, 11:03:23 am
Which events? The window's ones (sf::Event)?
Title: Linux Threading Issue
Post by: Jalfor on February 17, 2012, 11:12:30 am
Yes, I should have said. the

Code: [Select]
while (App.GetEvent(Event))

bit is what I need to get out of the that thread. Of course, I could just put it in the other thread but then I don't see how to access it as I can't think of a way to pass a pointer's address from the thread to the main function
Title: Linux Threading Issue
Post by: Laurent on February 17, 2012, 11:25:22 am
GetEvent must be called in the same thread where the window was created, that's a limitation of some OSes. If I remember correctly, on OS X, windows and events are even restricted to the main thread.
Title: Linux Threading Issue
Post by: Jalfor on February 17, 2012, 01:08:29 pm
So, I have to put all the display stuff and event handling stuff in the main thread and all the rest in different threads.

Thanks, as usual, you're a great help
Title: Linux Threading Issue
Post by: Laurent on February 17, 2012, 01:11:43 pm
Quote
So, I have to put all the display stuff and event handling stuff in the main thread and all the rest in different threads

There's no restriction on the "display stuff" -- whatever you put in this expression.