Re: winsock2 & wxWidgets: application hangs after reading UDP datagram,
then accessing wxTextCtrl
David,
David Schwartz wrote:
I think your problem is this:
1) Call the thread that sends the datagram thread A. It sends the
datagram and then blocks waiting for thread B to terminate. This
thread is operating from the frame, so it holds a lock on the frame.
2) Thread B gets the datagram and tries to access 'txtl'. The problem
is that thread A holds a lock on the frame. So thread B must wait
until thread A releases the lock.
At this point, thread A is waiting for thread B to finish, but thread
B cannot finish until it gets the frame lock, but thread A holds the
frame lock.
After some further testing, I have pinpointed the problem, and it was
exactly what you said. The following (reduced) example proves that the
whole thing isn't even related to the socket library, but solely happens
to do the mentioned frame lock. Thanks a lot! Now I need to find a way
around this :)
Best Regards,
Lars
*** code from here ***
#include <iostream>
using namespace std;
#include <boost/thread/thread.hpp>
#include "wx/wx.h"
#include <wx/string.h>
#include <wx/textctrl.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/button.h>
#include <wx/sizer.h>
#include <wx/frame.h>
class mainFrame : public wxFrame
{
protected:
// Virtual event handlers, overide them in your derived class
virtual void OnToggle( wxCommandEvent& event ){ event.Skip(); }
public:
wxButton* cmd1;
wxTextCtrl* txt1;
mainFrame( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString&
title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const
wxSize& size = wxSize( 500,300 ), long style =
wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL );
~mainFrame();
};
class debuggingGUImainFrame : public mainFrame
{
protected:
void OnToggle( wxCommandEvent& event );
public:
debuggingGUImainFrame( wxWindow* parent );
};
mainFrame::mainFrame( wxWindow* parent, wxWindowID id, const wxString&
title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame(
parent, id, title, pos, size, style )
{
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
wxBoxSizer* sizerMain;
sizerMain = new wxBoxSizer( wxVERTICAL );
txt1 = new wxTextCtrl( this, wxID_ANY, wxT("1"), wxDefaultPosition,
wxDefaultSize, 0 );
sizerMain->Add( txt1, 0, wxALL, 5 );
cmd1 = new wxButton( this, wxID_ANY, wxT("toggle"), wxDefaultPosition,
wxDefaultSize, 0 );
sizerMain->Add( cmd1, 0, wxALL, 5 );
this->SetSizer( sizerMain );
this->Layout();
// Connect Events
cmd1->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(
mainFrame::OnToggle ), NULL, this );
}
mainFrame::~mainFrame()
{
// Disconnect Events
cmd1->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(
mainFrame::OnToggle ), NULL, this );
}
/* *** */
debuggingGUImainFrame *mainWindow;
boost::thread *myThread;
/* *** */
void demonstrateFrameLock()
{
sleep (1);
cout << "child thread: taking a nap (2 seconds)" << endl;
sleep (2);
cout << "child thread: woke up!" << endl;
cout << "child thread: mainWindow->txt1->GetValue = " <<
mainWindow->txt1->GetValue() << endl;
cout << "child thread: thread finished" << endl;
}
/* *** */
debuggingGUImainFrame::debuggingGUImainFrame( wxWindow* parent )
:
mainFrame( parent )
{
}
void debuggingGUImainFrame::OnToggle( wxCommandEvent& event )
{
myThread = new boost::thread(&demonstrateFrameLock);
cout << "main thread: sleeping 5 seconds" << endl;
sleep (5);
cout << "main thread: done sleeping" << endl;
// cout << "main thread: waiting for child thread to end" << endl;
// myThread->join();
delete myThread;
myThread = 0;
cout << "main thread: thread finished" << endl;
}
/* *** */
class debuggingApp : public wxApp
{
virtual bool OnInit();
};
DECLARE_APP(debuggingApp)
IMPLEMENT_APP(debuggingApp)
bool debuggingApp::OnInit()
{
mainWindow = new debuggingGUImainFrame((wxFrame *)NULL); //, -1,
_T("debugging"), wxPoint(50,50), wxSize(450,340) );
mainWindow->Show (TRUE);
SetTopWindow (mainWindow);
return TRUE;
}