xcb Unknown Sequence while processing reply

Do you have a typical platform dependent issue you're battling with ? Ask it here. Make sure you mention your platform, compiler, and wxWidgets version.
Post Reply
Rick
Knows some wx things
Knows some wx things
Posts: 33
Joined: Fri Sep 02, 2016 12:26 pm

xcb Unknown Sequence while processing reply

Post by Rick » Thu Mar 28, 2019 8:35 pm

Hello,

I'm having a problem with my application. When run on a terminal server which is accessed via ThinClients over X2Go I'm getting the following errors:

[xcb] Unknown sequence number while processing reply
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
../../src/xcb_io.c:643: _XReply: Assertion »!xcb_xlib_threads_sequence_lost« failed.

RITICAL **: 14:51:54.188: draw_box: assertion 'height >= -1' failed
The program received an X Window System error.
This probably reflects a bug in the program.
The error was 'RenderBadPicture (invalid Picture parameter)'.
(Details: serial 6881 error_code 143 request_code 139 minor_code 7)
(Note to programmers: normally, X errors are reported asynchronously;
that is, you will receive the error a while after causing it.
To debug your program, run it with the --sync command line
option to change this behavior. You can then get a meaningful
backtrace from your debugger if you break on the gdk_x_error() function.)


I can't really reproduce the crash. It just happens randomly after hours. This error seems to have something to do with threads. I just can't figure out what I'm doing wrong. Should I call this XInitThreads function somewhere? Should I use special linking flags when compiling my programme?

Am I doing anything wrong with my threads? I'm using them in my DAO class which is based on the wxThread example:

Code: Select all

// Member variables of Dao class
DbHelper dbh; // Class that communicates with the database (libpqxx)
std::map<int, MyThread*> mThreads; // Keep tracks of the threads we've spawned
wxEvtHandler *m_pHandler;

// All the functions in the Dao class are like this
void Dao::Foo() {
    wxEvtHandler *handler = m_pHandler;
    std::future<void> future = std::async(std::launch::async, [this, handler] {
        wxThreadEvent event(wxEVT_THREAD, THREAD_DATA_READY);
        event.SetInt(ID_FOO);
        event.SetPayload<MyModel>(dbh.Bar());
        wxQueueEvent(handler, event.Clone());
    });
    RunThread(GET_GOAS, std::move(future), handler);
}
Dao::MyThread* Dao::RunThread(int taskId, std::future<void> future, wxEvtHandler *handler) {
    // MyThread is a detached wxThread
     MyThread *thread = new MyThread(this, taskId, std::move(future), handler); 
    if (thread->Run() != wxTHREAD_NO_ERROR) {
        wxLogError(wxString::Format("Can't create thread with taskID %d.", taskId));
        delete thread;
        return NULL;
    }
    mThreads.emplace(thread->GetId(), thread);
    return thread;
}
wxThread::ExitCode Dao::MyThread::Entry() {
    wxLogInfo("Spawning thread with ID %ld and TaskID %d", GetId(), mTaskId);
    bool error = false;
    wxString msg = "Done";
    try {
        std::future_status status = mFuture.wait_for(std::chrono::milliseconds(0));
        while (!TestDestroy()) {
            if (status == std::future_status::ready) break;
            wxThreadEvent event(wxEVT_THREAD, THREAD_UPDATE);
            event.SetInt(mTaskId);
            event.SetExtraLong(GetId());
            // m_pHandler should be OK here.
            if (m_pHandler) {
                wxQueueEvent(m_pHandler, event.Clone());
            }
            status = mFuture.wait_for(std::chrono::milliseconds(100));
        }
        if (status == std::future_status::ready) mFuture.get();
    } catch (...) { // Catch the exceptions that my be raised in the future (such as pqxx::exception)
         wxLogError(wxString::Format("TaskID=%d - %s", mTaskId, e.what()));
        msg = "Error";
    }

    wxThreadEvent event(wxEVT_THREAD, THREAD_TERMINATED);
    event.SetString(msg);
    event.SetInt(mTaskId);
    event.SetExtraLong(GetId());
    if (error) {
        event.SetId(THREAD_ERROR);
    }
    // signal the event handler that this thread is going to be destroyed
    if (m_pHandler) {
        wxQueueEvent(m_pHandler, event.Clone());
    }
    return (wxThread::ExitCode)0; // success
}
The Dao is used like this:

Code: Select all

/**
* Get a reference to the dao object.
*  Sets the DAO's event handler so the thread events are queued in the right handler. 
* @param who the calling event handler
* @return a reference to the DAO
*/
Dao& MyApp::GetDao(wxEvtHandler *who) {
      mDao.SetHandler(who);
      return mDao;
}
// In a class deriving from e.g. wxPanel:
wxGetApp().GetDao(this).Foo(); 

void MyPanel::OnThreadResult(wxThreadEvent &evt){
  switch(evt.GetInt()){
    case Dao::ID_FOO:
      MyModel m=evt.GetPayload<MyModel>();
     // Do stuff
     break;
     //case ID_BAR:
    // ...
  }
}

ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 3607
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: xcb Unknown Sequence while processing reply

Post by ONEEYEMAN » Fri Mar 29, 2019 2:39 pm

Hi,
Can you compile and run the thread sample?

Thank you.

Rick
Knows some wx things
Knows some wx things
Posts: 33
Joined: Fri Sep 02, 2016 12:26 pm

Re: xcb Unknown Sequence while processing reply

Post by Rick » Fri Mar 29, 2019 9:09 pm

Yes sure. Are you suggesting to modify the sample and run it like my programme to see if it crashes after X hours, too?

ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 3607
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: xcb Unknown Sequence while processing reply

Post by ONEEYEMAN » Fri Mar 29, 2019 9:23 pm

Hi,
First try the unmodified version.
And then try to make it crush by bringing in the code from your program...

And when you succeed - post the results here.

Thank you.

User avatar
doublemax
Moderator
Moderator
Posts: 14314
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: xcb Unknown Sequence while processing reply

Post by doublemax » Sat Mar 30, 2019 12:16 am

wxWidgets doesn't allow any GUI calls from secondary threads. Are you sure you're not doing that anywhere?
Use the source, Luke!

Rick
Knows some wx things
Knows some wx things
Posts: 33
Joined: Fri Sep 02, 2016 12:26 pm

Re: xcb Unknown Sequence while processing reply

Post by Rick » Mon Apr 01, 2019 9:29 am

Apart from passing the calling wxWindow/wxEventHandler to the Dao and thus to the thread (see code in OP) for using wxQueueEvent() I'm not accessing any GUI elements. I only found wxGetApp().GetFoo() in one function in the DbHelper class. Is that safe or could that cause problems (GetFoo() is a simple getter)?
The confusing thing is that the programme doesn't crash when invoking that function. It crashes after e.g., 6 hours of idle time.

I've serialised my Dao class in that I'm not spawning MyThread anymore but have a loop that waits for the future in the main thread. The app ran the entire weekend without crashing.
Seems to be something with my threads but I cannot figure out what it is.

ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 3607
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: xcb Unknown Sequence while processing reply

Post by ONEEYEMAN » Mon Apr 01, 2019 9:39 pm

Hi,
What is the point of passing the pointer to the object to the thread when you can't call any functions on it?

NO GUI OPERATIONS IS ALLOWED ON THE SECONDARY THREAD!!! GUI CALLS ARE NOT THREAD-SAFE!!!!!

Thank you.

P.S.:
2doublemax,
This has to be written as a pinned thread in all forums. ;-)
But then again - "Somebody will always jack things up" (C) (my old Army instructor).

Rick
Knows some wx things
Knows some wx things
Posts: 33
Joined: Fri Sep 02, 2016 12:26 pm

Re: xcb Unknown Sequence while processing reply

Post by Rick » Tue Apr 02, 2019 8:51 am

I am aware of that.
The point of passing the pointer is to explicitly send the wxThreadEvents to that EventHandler. That's literally what is done in the wxThread sample...

If you find any flaws in the code I've posted above it'd be nice to point them out. E.g., is calling wxGetApp() safe from a secondary thread? Is the concept with std::future and lambdas (and the way I pass/capture the values) ok?

User avatar
doublemax
Moderator
Moderator
Posts: 14314
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: xcb Unknown Sequence while processing reply

Post by doublemax » Tue Apr 02, 2019 9:21 am

is calling wxGetApp() safe from a secondary thread?
Yes.
Is the concept with std::future and lambdas (and the way I pass/capture the values) ok?
I don't know. But i'm not sure if mixing STL and wx threading code is a good idea. Maybe you should choose one and stick with it.
Use the source, Luke!

ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 3607
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: xcb Unknown Sequence while processing reply

Post by ONEEYEMAN » Tue Apr 02, 2019 3:33 pm

Hi,
So did you try building the thread sample and run it in you environment?
Just try it un-modified first and then try to bring some code from your project until it (hopefully) crash.
Or do it vice versa - strip down your project until it doesn't crash.

Thank you.

Rick
Knows some wx things
Knows some wx things
Posts: 33
Joined: Fri Sep 02, 2016 12:26 pm

Re: xcb Unknown Sequence while processing reply

Post by Rick » Wed Apr 03, 2019 8:27 am

Hi,
I did it the other way around: I'm not creating a wxThread that waits for my futue anymore. Now I'm having a loop on the main thread that waits for the future:

Code: Select all

Dao::MyThread* Dao::RunThread(int taskId, std::future<void> future, wxEvtHandler *handler) {
// wxThreadDataReady event is sent from the future via wxQueueEvent
try{
while(NotTimedOut){
     if (status == std::future_status::ready) break;
     // Create wxThreadUpdate event
     // handler->ProcessEvent()
        status = mFuture.wait_for(std::chrono::milliseconds(100));
   
        if (status == std::future_status::ready){
         mFuture.get();
         }
    }catch(...){
    // Create wxThreadError event
    // handler->ProcessEvent();
    }
        return NULL
}

This seemed to solve the problem. As I said before, done that and it worked for a couple of days without crashing.

Post Reply