Crash with boost::thread Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
mspoerr
Experienced Solver
Experienced Solver
Posts: 50
Joined: Sat Mar 15, 2008 9:17 pm

Crash with boost::thread

Post 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
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post 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.
Use the source, Luke!
mspoerr
Experienced Solver
Experienced Solver
Posts: 50
Joined: Sat Mar 15, 2008 9:17 pm

Post 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
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post 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
Use the source, Luke!
mspoerr
Experienced Solver
Experienced Solver
Posts: 50
Joined: Sat Mar 15, 2008 9:17 pm

Post 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
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post 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?
Use the source, Luke!
mspoerr
Experienced Solver
Experienced Solver
Posts: 50
Joined: Sat Mar 15, 2008 9:17 pm

Post 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
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post 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
Use the source, Luke!
mspoerr
Experienced Solver
Experienced Solver
Posts: 50
Joined: Sat Mar 15, 2008 9:17 pm

Post 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
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post 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.
Use the source, Luke!
mspoerr
Experienced Solver
Experienced Solver
Posts: 50
Joined: Sat Mar 15, 2008 9:17 pm

Post by mspoerr »

ok - thank you very much. I will try and come back later ;)

/mspoerr
Frank
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 211
Joined: Sat Jan 01, 2005 6:19 pm

Post 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); }
};
mspoerr
Experienced Solver
Experienced Solver
Posts: 50
Joined: Sat Mar 15, 2008 9:17 pm

Post by mspoerr »

Thank you for the hint. I will check it out.

/mspoerr
mspoerr
Experienced Solver
Experienced Solver
Posts: 50
Joined: Sat Mar 15, 2008 9:17 pm

Post 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
Frank
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 211
Joined: Sat Jan 01, 2005 6:19 pm

Post 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)) // ...
Post Reply