Page 1 of 2

Crash with boost::thread

Posted: Mon Jun 29, 2009 3:20 pm
by mspoerr
Hello,

I am using wxwidgets together with boost::thread. The Thread is a worker thread which sends some Events to the GUI:

Thread creation:

Code: Select all

thrd = boost::thread(boost::bind(workerFunction,this));
Send Message to the GUI:

Code: Select all

wxPostEvent(loWindow, event);
wxSafeYield();
Under Windows I don't see any problems, but when starting the application under Linux (Ubuntu 8.10), it stops with the following error message:
_XCBUnlockDisplay: Assertion `xcb_get_request_sent(dpy->xcb->connection) == dpy->request' failed.
Aborted
What am I missing? When the workerFunction is not started in a thread, it works without problems.
I don't touch the GUI directly - only via wxPostevent().

Thanks,
/mspoerr

Posted: Mon Jun 29, 2009 3:55 pm
by doublemax
i don't know if that is the reason for your problem, but calling wxSafeYield from a secondary thread doesn't look right.

Posted: Mon Jun 29, 2009 4:07 pm
by mspoerr
when I don't do this, the app also crashes in Windows and earlier in Linux. I thought I have to use it, becasue in the documentation I found the following hint:
Yields control to pending messages in the windowing system. This can be useful, for example, when a time-consuming process writes to a text window. Without an occasional yield, the text window will not be updated properly, and on systems with cooperative multitasking, such as Windows 3.1 other processes will not respond.
Maybe I have to use it in the Log Window?

Thanks,
/mspoerr

Posted: Mon Jun 29, 2009 4:14 pm
by doublemax
mspoerr wrote:I thought I have to use it, becasue in the documentation I found the following hint:
Yields control to pending messages in the windowing system. This can be useful, for example, when a time-consuming process writes to a text window. Without an occasional yield, the text window will not be updated properly, and on systems with cooperative multitasking, such as Windows 3.1 other processes will not respond.
this applies when you have a long-running task in the main thread, then you can call Yield() to give the application the chance to process events and update its gui. In a secondary thread you don't need it (because the main thread is not blocked) and it's probably bad because it would start processing events in the secondary thread.
when I don't do this, the app also crashes in Windows and earlier in Linux.
then i think the problem lies somewhere else.
Maybe I have to use it in the Log Window?
i don't know what log window you're talking about

Posted: Mon Jun 29, 2009 6:03 pm
by mspoerr
this applies when you have a long-running task in the main thread, then you can call Yield() to give the application the chance to process events and update its gui. In a secondary thread you don't need it (because the main thread is not blocked) and it's probably bad because it would start processing events in the secondary thread.
oh -ok.

With Log Window I mean a text window, where the events from the thread are posted -> Thread runs and is very chatty. All output is sent via wxPostEvent to the Log Window, where it is displayed. What would be a good solution for this? For what do I need to take care of?

Thanks,
mspoerr

Posted: Mon Jun 29, 2009 6:29 pm
by doublemax
first you should find out if this is really the cause for the crash. Does everything work fine if you comment out the wxPostEvent call?

What kind of event do you send? A custom event or a standard wxCommandEvent? wxString is not thread-safe, so sending strings using wxCommandEvent::SetString is a potential reason for your crash.

But then again, these kind of crashes are usually more random, so it's possible that your problem is really somewhere else. Do you have a backtrace?

Posted: Mon Jun 29, 2009 8:15 pm
by mspoerr
when not posting the event, the application doesn't crash. I use a wxCommandEvent with a string:

Code: Select all

void Ersetzer::schreibeLog(int type, string logEintrag, int farbe, int format, int groesse)
{
	if (logAusgabe != NULL)
	{
		evtData evtDat;
		evtDat.farbe = farbe;
		evtDat.format = format;
		evtDat.groesse = groesse;
		evtDat.logEintrag = logEintrag;
		evtDat.type = type;
		
		wxCommandEvent event(wkEVT_SCHREIBELOG);
		event.SetClientData(&evtDat);
		wxPostEvent(logAusgabe, event);

		//wxSafeYield();
	}
}
How should I change this to make it work?

Thanks,
mspoerr

Posted: Mon Jun 29, 2009 8:31 pm
by doublemax
you should have posted that code earlier, this can't work at all. You're only writing the pointer &evtDat into the event data, the data itself is a local variable, so the pointer will be invalid when the event gets processed.

You should create a custom event for this purpose.
http://docs.wxwidgets.org/stable/wx_eve ... stomevents

Posted: Mon Jun 29, 2009 8:49 pm
by mspoerr
You're only writing the pointer &evtDat into the event data, the data itself is a local variable, so the pointer will be invalid when the event gets processed.
sounds reasonable
You should create a custom event for this purpose.
What is the advantage of a custom event?

Thanks,
mspoerr

Posted: Mon Jun 29, 2009 8:55 pm
by doublemax
you need an own event class if you want to send more complex data. For that it's important to overwrite wxEvent::Clone() with your own version that makes sure all the data is copied correctly.

Posted: Mon Jun 29, 2009 8:57 pm
by mspoerr
ok - thank you very much. I will try and come back later ;)

/mspoerr

Posted: Tue Jun 30, 2009 11:08 am
by Frank
Since you're using Boost, maybe I can help you out with a generic event, wich uses boost::any, so you can post every data you want:

Code: Select all

class DataEvent : public wxEvent
{
   boost::any data;

public:
   DataEvent () : wxEvent(0, wxEVT_DATA) { }
   DataEvent (const boost::any& data) : wxEvent(0, wxEVT_DATA), data(data) {  }
   ~wxGDDataEvent () { }

   wxEvent* Clone () const { return new DataEvent(*this); }

   void SetData (const boost::any& data) { this->data = data; }
   boost::any GetData () const { return data; }

   template<typename T> T GetData () const { return boost::any_cast<T>(data); }
};

Posted: Tue Jun 30, 2009 6:37 pm
by mspoerr
Thank you for the hint. I will check it out.

/mspoerr

Posted: Tue Jun 30, 2009 8:54 pm
by mspoerr
Stupid question: How to use the GetData() function? Would you please so kind to post a sample?
I always get an compiler error: 'conversion' : cannot convert from 'boost::any' to 'std::string'

Thanks,
mspoerr

Posted: Wed Jul 01, 2009 2:53 pm
by Frank
You can either use boost::any_cast or the template-function:

Code: Select all

// Option 1
std::string str = event.GetData<std::string>();

// Option 2
boost::any data = event.GetData();
std::string str = boost::any_cast<std::string>(data);

// When you need to check the type of the data you can use typeid:

if (data.type() == typeid(std::string)) // ...