winsock2 & wxWidgets: application hangs after reading UDP datagram,then accessing wxTextCtrl

L

Lars Uffmann

X-Post to comp.unix.programmer & comp.lang.c++
F'Up set to comp.lang.c++

Hi everyone!

I am sorry that I am not able to reduce the bug-reproducing code
further, I have been trying to debug this for 2 days at least. What I am
doing is: I have a minimal wxWidgets application (GUI code as generated
by wxFormBuilder at the bottom) with a frame mainFrane, a wxBoxSizer
sizerMain, a wxTextCtrl txt1 and a wxButton cmd1. Now on wxApp::OnInit,
I start a boost::thread that listens for a UDP datagram. The cmd1 button
will send a simple UDP packet (just 1 byte, value 0) so the thread can
finish, then call a join() on the thread to wait for it to exit.

After that I want to access the properties of the wxTextCtrl txt1. In
this case txt1->GetValue(). The very function worked fine just before
the recvfrom call in my thread function. Right AFTER that call, when the
UDP packet has been received, the program locks up IF I try to access
txt1->GetValue(). txt1->GetName() works fine just in the line before. If
I do not call this function, the application is fine and can be exited
normally. If I do not call recvfrom, I can access txt1->GetValue() just
fine.

Now the really strange thing is: if I play back a "REAL" UDP packet,
like the ones I am writing this application for, everything works just
fine: the recvfrom gets called, gets (part of) the packet, and then the
call to txt1->GetValue() yields the expected result, and the application
is healthy.

So does this mean that my usage of the socket function sendto(...) is
wrong, and that it causes undefined behaviour to send a single byte with
value 0 in a UDP datagram?

Or if not - what could possibly be causing this lockup? Complete code
following, sorry for the X-Post, but since it's a problem that occurs
upon combined usage of the socket library & wxWidgets (and
boost:thread), I think it makes sense to ask in both relevant groups.
Unless of course its a winsock2 problem that would not occur with linux
sockets...

In the attached code, please search for the comment line that says
/* LOCKUP HERE */

To compile this example you'll need wxwidgets, boost::thread and the
sockets library for your system - if that's not windows (sorry), have to
adjust the include for winsock2.h

Best Regards & TIA,

Lars Uffmann

code (3 files, latter 2 are output from wxFormBuilder, stripped of
comments and merged GUI & event handler classes to one file):

********** BEGIN debugging.cpp ***********
#define __USE_W32_SOCKETS
#include <winsock2.h>

#define BUFLEN 5120
#define PORT 6000

#include <iostream>
using namespace std;
#include <sstream>
#include <boost/thread/thread.hpp>

#include "wx/wx.h"

#include "debuggingGUI.h"

debuggingGUImainFrame *mainWindow;
boost::thread *THREAD_FileReceiver;

/* *** */

void sendEndOfStream()
{
struct sockaddr_in saLocalhost;
SOCKET sEndOfStream;
int slen = sizeof(saLocalhost);
char buf[10];

sEndOfStream = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sEndOfStream == INVALID_SOCKET) {
cout << "Invalid socket, failed to create socket" << endl;
return;
}

memset((char *) &saLocalhost, 0, sizeof (saLocalhost));
saLocalhost.sin_family = AF_INET;
saLocalhost.sin_port = htons(PORT);
saLocalhost.sin_addr.s_addr = inet_addr ("127.0.0.1");

buf[0] = 0;
sendto(sEndOfStream, buf, 1, 0, (sockaddr *) &saLocalhost, slen);
closesocket (sEndOfStream);
}

int listenForAPacket() {
struct sockaddr_in si_me, si_other;
SOCKET s;
int slen = sizeof(si_other);
char buf[100];
int nRet;

s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s == INVALID_SOCKET) {
cout << "Invalid socket, failed to create socket" << endl;
return -2;
}

memset((char *) &si_me, 0, sizeof (si_me));
si_me.sin_family = AF_INET;
si_me.sin_port = htons(PORT);
si_me.sin_addr.s_addr = htonl(INADDR_ANY);

nRet = bind(s, (sockaddr *) &si_me, sizeof (si_me));
if (nRet == SOCKET_ERROR) {
cout << "Failed to bind socket" << endl;
closesocket (s);
return -2;
}

cout << "mainWindow = " << (int) mainWindow << endl;
cout << mainWindow->txt1->GetValue() << endl;
recvfrom (s, &buf[0], 10, 0, (sockaddr *) &si_other, &slen);

cout << "mainWindow = " << (int) mainWindow << endl;
cout << mainWindow->txt1->GetName() << endl;

/* LOCKUP HERE */
cout << mainWindow->txt1->GetValue() << endl;

closesocket(s);
return 1;
}

/* *** */

debuggingGUImainFrame::debuggingGUImainFrame( wxWindow* parent )
:
mainFrame( parent )
{
}

void debuggingGUImainFrame::OnToggle( wxCommandEvent& event )
{
sendEndOfStream();
cout << "waiting for thread to end" << endl;
THREAD_FileReceiver->join();
cout << "thread finished" << endl;
}


/* *** */


class debuggingApp : public wxApp
{
virtual bool OnInit();
};

DECLARE_APP(debuggingApp)
IMPLEMENT_APP(debuggingApp)

bool debuggingApp::OnInit()
{
// Initialize WinSock2.2 DLL
// low-word = major, hi-word = minor
WSADATA wsaData = {0};
WORD wVer = MAKEWORD(2,2);

int nRet = WSAStartup (wVer, &wsaData);
if (nRet == SOCKET_ERROR) {
// WSAGetLastError()
cout << "Failed to init Winsock library" << endl;
return false;
}
mainWindow = new debuggingGUImainFrame((wxFrame *)NULL); //, -1,
_T("debugging"), wxPoint(50,50), wxSize(450,340) );

mainWindow->Show (TRUE);
SetTopWindow (mainWindow);
THREAD_FileReceiver = new boost::thread(&listenForAPacket);

return TRUE;
}
*********** END debugging.cpp ************

********** BEGIN debuggingGUI.h ***********
#ifndef __debuggingGUI__
#define __debuggingGUI__

#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
{
private:

protected:
wxButton* cmd1;
// Virtual event handlers, overide them in your derived class
virtual void OnToggle( wxCommandEvent& event ){ event.Skip(); }

public:
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 );
};

#endif //__debuggingGUI__
*********** END debuggingGUI.h ************

********** BEGIN debuggingGUI.cpp ***********
#include "debuggingGUI.h"

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 );
}
*********** END debuggingGUI.cpp ************
 
A

AnonMail2005

X-Post to comp.unix.programmer & comp.lang.c++
F'Up set to comp.lang.c++

Hi everyone!

I am sorry that I am not able to reduce the bug-reproducing code
further, I have been trying to debug this for 2 days at least. What I am
doing is: I have a minimal wxWidgets application (GUI code as generated
by wxFormBuilder at the bottom) with a frame mainFrane, a wxBoxSizer
sizerMain, a wxTextCtrl txt1 and a wxButton cmd1. Now on wxApp::OnInit,
I start a boost::thread that listens for a UDP datagram. The cmd1 button
will send a simple UDP packet (just 1 byte, value 0) so the thread can
finish, then call a join() on the thread to wait for it to exit.

After that I want to access the properties of the wxTextCtrl txt1. In
this case txt1->GetValue(). The very function worked fine just before
the recvfrom call in my thread function. Right AFTER that call, when the
UDP packet has been received, the program locks up IF I try to access
txt1->GetValue(). txt1->GetName() works fine just in the line before. If
I do not call this function, the application is fine and can be exited
normally. If I do not call recvfrom, I can access txt1->GetValue() just
fine.

Now the really strange thing is: if I play back a "REAL" UDP packet,
like the ones I am writing this application for, everything works just
fine: the recvfrom gets called, gets (part of) the packet, and then the
call to txt1->GetValue() yields the expected result, and the application
is healthy.

So does this mean that my usage of the socket function sendto(...) is
wrong, and that it causes undefined behaviour to send a single byte with
value 0 in a UDP datagram?

Or if not - what could possibly be causing this lockup? Complete code
following, sorry for the X-Post, but since it's a problem that occurs
upon combined usage of the socket library & wxWidgets (and
boost:thread), I think it makes sense to ask in both relevant groups.
Unless of course its a winsock2 problem that would not occur with linux
sockets...

In the attached code, please search for the comment line that says
   /* LOCKUP HERE */

To compile this example you'll need wxwidgets, boost::thread and the
sockets library for your system - if that's not windows (sorry), have to
adjust the include for winsock2.h

Best Regards & TIA,

    Lars Uffmann

code (3 files, latter 2 are output from wxFormBuilder, stripped of
comments and merged GUI & event handler classes to one file):

********** BEGIN debugging.cpp ***********
#define __USE_W32_SOCKETS
#include <winsock2.h>

#define BUFLEN 5120
#define PORT 6000

#include <iostream>
using namespace std;
#include <sstream>
#include <boost/thread/thread.hpp>

#include "wx/wx.h"

#include "debuggingGUI.h"

debuggingGUImainFrame *mainWindow;
boost::thread *THREAD_FileReceiver;

/* *** */

void sendEndOfStream()
{
   struct sockaddr_in saLocalhost;
   SOCKET sEndOfStream;
   int slen = sizeof(saLocalhost);
   char buf[10];

   sEndOfStream = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
   if (sEndOfStream == INVALID_SOCKET) {
     cout << "Invalid socket, failed to create socket" << endl;
return;
   }

   memset((char *) &saLocalhost, 0, sizeof (saLocalhost));
   saLocalhost.sin_family = AF_INET;
   saLocalhost.sin_port = htons(PORT);
   saLocalhost.sin_addr.s_addr = inet_addr ("127.0.0.1");

   buf[0] = 0;
   sendto(sEndOfStream, buf, 1, 0, (sockaddr *) &saLocalhost, slen);
   closesocket (sEndOfStream);

}

int listenForAPacket() {
   struct sockaddr_in si_me, si_other;
   SOCKET s;
   int slen = sizeof(si_other);
   char buf[100];
   int nRet;

   s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
   if (s == INVALID_SOCKET) {
     cout << "Invalid socket, failed to create socket" << endl;
return -2;
   }

   memset((char *) &si_me, 0, sizeof (si_me));
   si_me.sin_family = AF_INET;
   si_me.sin_port = htons(PORT);
   si_me.sin_addr.s_addr = htonl(INADDR_ANY);

   nRet = bind(s, (sockaddr *) &si_me, sizeof (si_me));
   if (nRet == SOCKET_ERROR) {
     cout << "Failed to bind socket" << endl;
     closesocket (s);
return -2;
   }

   cout << "mainWindow = " << (int) mainWindow << endl;
   cout << mainWindow->txt1->GetValue() << endl;
   recvfrom (s, &buf[0], 10, 0, (sockaddr *) &si_other, &slen);

   cout << "mainWindow = " << (int) mainWindow << endl;
   cout << mainWindow->txt1->GetName() << endl;

   /* LOCKUP HERE */
   cout << mainWindow->txt1->GetValue() << endl;

   closesocket(s);
   return 1;

}

/* *** */

debuggingGUImainFrame::debuggingGUImainFrame( wxWindow* parent )
:
mainFrame( parent )
{

}

void debuggingGUImainFrame::OnToggle( wxCommandEvent& event )
{
   sendEndOfStream();
cout << "waiting for thread to end" << endl;
   THREAD_FileReceiver->join();
cout << "thread finished" << endl;

}

/* *** */

class debuggingApp : public wxApp
{
   virtual bool OnInit();

};

DECLARE_APP(debuggingApp)
IMPLEMENT_APP(debuggingApp)

bool debuggingApp::OnInit()
{
   // Initialize WinSock2.2 DLL
   // low-word = major, hi-word = minor
   WSADATA wsaData = {0};
   WORD wVer = MAKEWORD(2,2);

   int nRet = WSAStartup (wVer, &wsaData);
   if (nRet == SOCKET_ERROR) {
     // WSAGetLastError()
     cout << "Failed to init Winsock library" << endl;
return false;
   }
   mainWindow = new debuggingGUImainFrame((wxFrame *)NULL); //, -1,
_T("debugging"), wxPoint(50,50), wxSize(450,340) );

   mainWindow->Show (TRUE);
   SetTopWindow (mainWindow);
   THREAD_FileReceiver = new boost::thread(&listenForAPacket);

   return TRUE;}

*********** END debugging.cpp ************

********** BEGIN debuggingGUI.h ***********
#ifndef __debuggingGUI__
#define __debuggingGUI__

#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
{
   private:

   protected:
     wxButton* cmd1;
     // Virtual event handlers, overide them in your derived class
     virtual void OnToggle( wxCommandEvent& event ){ event.Skip(); }

   public:
     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 );

};

#endif //__debuggingGUI__
*********** END debuggingGUI.h ************

********** BEGIN debuggingGUI.cpp ***********
#include "debuggingGUI.h"

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 );}

*********** END debuggingGUI.cpp ************

wxWidgets and sockets are OT in this newsgroup.
 
L

Lars Uffmann

wxWidgets and sockets are OT in this newsgroup.

That is a matter of perspective, especially when the bug is somewhere in
between and might also involve boost::thread usage.

However, a fullquote followed by a single line of a useless "smart"
remark is always OT.

....

Lars
 
A

AnonMail2005

That is a matter of perspective, especially when the bug is somewhere in
between and might also involve boost::thread usage.

However, a fullquote followed by a single line of a useless "smart"
remark is always OT.

...

   Lars

My news reader does the quoting for me automagically. But don't
worry, you will get used to it.
 
R

red floyd

(e-mail address removed) wrote: [redacted]

However, a fullquote followed by a single line of a useless "smart"
remark is always OT.

...

Lars

My news reader does the quoting for me automagically. But don't
worry, you will get used to it.

Wrong. *YOU* will get used to the etiquette of this newsgroup.

http://www.parashift.com/c++-faq-lite/how-to-post.html#faq-5.4

And, great, your newsreader quotes the whole post. So what, so does
mine. I edit it before posting. You can do the same.
 
D

David Schwartz

I am sorry that I am not able to reduce the bug-reproducing code
further, I have been trying to debug this for 2 days at least. What I am
doing is: I have a minimal wxWidgets application (GUI code as generated
by wxFormBuilder at the bottom) with a frame mainFrane, a wxBoxSizer
sizerMain, a wxTextCtrl txt1 and a wxButton cmd1. Now on wxApp::OnInit,
I start a boost::thread that listens for a UDP datagram. The cmd1 button
will send a simple UDP packet (just 1 byte, value 0) so the thread can
finish, then call a join() on the thread to wait for it to exit.

UDP is unreliable. If the datagram is dropped/lost, the thread will
not exit. Some platforms do offer reliable local UDP, but the platform
you are using may not.
After that I want to access the properties of the wxTextCtrl txt1. In
this case txt1->GetValue(). The very function worked fine just before
the recvfrom call in my thread function. Right AFTER that call, when the
UDP packet has been received, the program locks up IF I try to access
txt1->GetValue(). txt1->GetName() works fine just in the line before. If
I do not call this function, the application is fine and can be exited
normally. If I do not call recvfrom, I can access txt1->GetValue() just
fine.

Perhaps the thread that sends the datagram does something to 'txtl'?
Now the really strange thing is: if I play back a "REAL" UDP packet,
like the ones I am writing this application for, everything works just
fine: the recvfrom gets called, gets (part of) the packet, and then the
call to txt1->GetValue() yields the expected result, and the application
is healthy.

That definitely sounds like the problem is something else the thread
that sends the UDP datagram does.

[snip]

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.

DS
 
L

Lars Uffmann

Hi David,

David said:
UDP is unreliable. If the datagram is dropped/lost, the thread will
not exit. Some platforms do offer reliable local UDP, but the platform
you are using may not.

The datagram is definitely arriving, my code is doing a cout to verify
it has reached the step after recvfrom :)
Perhaps the thread that sends the datagram does something to 'txtl'?
Well - the _thread_ sending the datagram is the main wxWindows thread
(event handler), but the function sending the datagram isn't doing
anything to txt1.
I think your problem is this:
[...]
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.

Wow. Very nice analysis. This might indeed be the problem here. It
definitely gave me a new insight into the situation. And it would
explain the difference between receiving a "selfmade" UDP packet
(because only then thread A is waiting for thread B) and the played back
packets.

Thank you very much, I think I'll be able to work around this now (got
pointed to custom events in wxwindows newsgroup).

Best Regards,

Lars
 
L

Lars Uffmann

David,

David said:
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;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top