Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to combat "Fatal IO error 11 (Resource temporarily unavailable) on X server" in multithreaded gtkmm application?

I am attempting to write a gtkmm application that uses C++11 multithreading. However, i keep running into Fatal IO error 11 (Resource temporarily unavailable) on X server error.

I have several Gtk::Image objects on my window. Each one is in its own Gtk::EventBox and periodically i have to change the image. To do that i have created a class that holds the event box for the specific block, and it has a function that removes the previous image, generates the new one and places it there.

Here's a block of code:

while (lock_flag.test_and_set()) {} // std::atomic_flag lock
// ...
std::cerr << 1;
eventBox->foreach(
    [eb = this->eventBox](Gtk::Widget& w)
    {
        eb->Gtk::Container::remove(w);
    }
);
std::cerr << 2;
eventBox->add(*im);
std::cerr << 3;
eventBox->show_all_children();
std::cerr << 4;
// ...
lock_flag.clear();

When error 11 occurs some of the numbers do not get printed to std::cerr, but where the problem happens is different each time (i have recently observed it crashing after 12 and after 123). Thus i come to the conclusion that the resource that is being used somewhere is not the image, but the eventBox. But after initialisation of the program it is not accessed anywhere outside of this function, and this function is wrapped with the std::atomic_flag lock.

Questions: What can be a reason for such behaviour? Can i ensure that it doesn't happen? Or can i catch this error and expect to recover from it?

Edits:

I have attempted

  1. I tried to change from using std::thread to Glib::Threads::Thread, but to no avail, still getting the same error.
  2. Having read this i have attempted to add GDK_SYNCHRONIZE to environment, this has generated [xcb] Unknown request in queue while dequeuing/[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called error. This lead me to this post, after which i have attempted to call XInitThreads() before starting the new thread (both via Glib::Threads::Thread and std::thread), but this did nothing positive; except that once by some fluke the thread has actually executed the entire function (displayed '4' on screen), but then still managed to die with the same error 11 message.
like image 528
v010dya Avatar asked Jul 12 '15 10:07

v010dya


2 Answers

GTK is not thread safe. You can use a global lock to access GTK from threads, but the best practice is to only invoke GTK functions from the main thread. You can use Glib::signal_idle().connect and Glib::MainContext::invoke() for that.

like image 110
Phillip Avatar answered Nov 10 '22 20:11

Phillip


In the end here is how i've resolved all the problems.

Going through the link provided by Phillip i have found out about Glib::signal_timeout(), and that has enabled me to completely rethink the concept of parallelism in my code.

Here is what i had to start with:

if(running) return;
running = true;

static bool firstTime = true;
if(firstTime)
{
    XInitThreads();
    firstTime=false;
}

std::function<void()> f = [this] () -> void
{
    while(running)
    {
        this->takeStep();
        std::this_thread::sleep_for(std::chrono::milliseconds(300));
    }
};

std::thread(f).detach();

and this could easily be rewritten as:

if(running) return;
running = true;

runningHandle = Glib::signal_timeout().connect( sigc::mem_fun(*this, &ArtificialIntelligence::takeStep), 300 );

I then only needed to add runningHandle.disconnect(); to my pause function, and all began working wonderfully. In fact the speed of GUI response has gone up.

So if anybody else is trying to do "take an action, then sleep" process, this is a much better alternative. There are of course applications where there is no set periodicity, and then some other solution should be sought.

like image 2
v010dya Avatar answered Nov 10 '22 20:11

v010dya