Separate thread is populating wxListCtrl in main thread

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.
Post Reply
Virchanza
Experienced Solver
Experienced Solver
Posts: 78
Joined: Sun Jul 19, 2009 6:12 am

Separate thread is populating wxListCtrl in main thread

Post by Virchanza » Sun Jul 19, 2009 7:04 am

I've got experience writing multi-threaded commandline programs with the pthreads library, but now I'm taking one of my command line programs and turning it into a GUI program, so I'm using wxWidgets :D (It's absolutely fantastic by the way, and with wxFormBuilder it's absolutely amazing).

So anyway, here's the story...

I have a main dialog box which contains a wxListCtrl.

In the main dialog box, the user enters the name of a network card into a text box, and then clicks a button.

When the user clicks the button, I want to start a new thread. The new thread will read packets from the specified network card, and will write these packets as items into the wxListCtrl on the main dialog box.

What I need to learn though, is how I go about getting the Sniffer thread to tell the main thread to add the stuff to the wxListCtrl... and I also haven't got a clue about what mutexes and so forth I need to lock when doing so.

I've written some code already. To simplify it, I've stripped all the networking code out of it and just replaced it with dummy calls such as a "sleep for 100 milliseconds, then write to the wxListCtrl".

My sniffer thread calls a synchronous function which reads a packet from the network card (meaning the function doesn't return until it's captured a packet), so it's accurate enough to replace it with a call to wxThread::Sleep in my simplified code.

Here's the header file I have for the thread that reads from the network card:

Code: Select all

#define H__SNIFFER

#include "wx/wx.h"

#if !wxUSE_THREADS
    #error "This sample requires thread support!"
#endif

#include "wx/thread.h"

#include "my_special_networking_header_you_dont_need_to_know_about.h"

class SnifferThread : public wxThread
{
public:

    EtherSockHandle const m_s;
    /* This is the handle I use for
       reading from the network card. */

    wxListCtrl *const m_listctrl;
    /* This is the wxListCtrl that's gonna
       get populated with network packets. */

public:

    SnifferThread(EtherSockHandle const s, wxListCtrl *listctrl)
        : m_s(s), m_listctrl(listctrl) {}

    virtual void *Entry()
    {
        for (;;)
        {
            m_listctrl->InsertItem(0,wxT("monkey"));

            wxThread::MilliSleep(30);
        }

        return 0;
};

#endif
I'm pretty sure that I shouldn't be calling wxListCtrl::InsertItem from within the child thread. Instead I'm supposed to somehow tell the main thread to do it for me. How exactly do I go about doing this? Something like wxPostEvent? Could somebody please give me a small code snippet?

And here's the code I have for when the button is clicked in the main dialog box:

Code: Select all

void monkey_programDialog::OnStartSniffer(wxCommandEvent &event)
{
        /* psniff is a global variable of type SnifferThread*
           s is a global variable of type EtherSockHandle
           m_listctrlMACS is a member variable of type wxListCtrl*
        */

        psniff = new SnifferThread(s, m_listctrlMACS);

        wxMessageBox(wxT("Thread Object New'd"));

        if ( psniff->Create() != wxTHREAD_NO_ERROR )
        {
            wxMessageBox(wxT("Thread Creation Failed"));
            delete psniff;
            psniff = 0;
        }
        else
        {
            if (psniff->Run() != wxTHREAD_NO_ERROR )
            {
                wxMessageBox(wxT("Thread Run Failed"));
                delete psniff;
                psniff = 0;
            }

            wxMessageBox(wxT("Thread is Running"));
        }
}
So I suppose my questions are as follows:
1) How do I "send a message" from the sniffer thread to the main thread telling it to add a certain item to the wxListCtrl? (I also need to send it the text of the item).
2) What mutexes, sempahores, whatever, do I need to play around with?

I'd appreciate if you could give a very small code example.

Also, I have another button on the main dialog box which turns off the sniffer thread. Is it OK to turn off the Sniffer Thread as follows?

Code: Select all

void monkey_programDialog::OnStopSniffer(wxCommandEvent &event)
{
    psniff->Delete();

    /* I don't do "delete psniff" because it gets deleted automatically */

    psniff = 0;
}
Presumbly, when the "Stop Sniffing" button is clicked, the Sniffer Thread will be waiting on the synchronous networking function to return. Will it be a problem if the thread is killed while it's waiting on the synchronous function to return?

When I have this code finished, I'm gonna work on writing another thread called the "Prober" thread. The Prober thread will read items from the wxListCtrl, and then will send packets out on the network interface.

In the Prober Thread, will I need to lock some sort of mutex for the wxListCtrl when I'm reading items from it? ...or do I somehow tell the main thread to read them for me?

Thanks for reading :)

DavidHart
Site Admin
Site Admin
Posts: 4046
Joined: Thu Jan 12, 2006 6:23 pm
Location: IoW, UK

Post by DavidHart » Sun Jul 19, 2009 10:14 am

Hi,
2) What mutexes, sempahores, whatever, do I need to play around with?
None. Just use events...
1) How do I "send a message" from the sniffer thread to the main thread telling it to add a certain item to the wxListCtrl? (I also need to send it the text of the item).
The thing you need to know about worker thread -> gui thread communication is: don't touch the gui direct from a worker thread. Non-gui classes are OK (as long as
they don't synchronously touch the gui).

Instead use wxEvents, asynchronously. For a simple notification, posting a simple event (with a specific ID) would suffice; but you want to pass more information, so you need a custom event. See http://wiki.wxwidgets.org/Custom_Events ... -_Method_4 for how to do this. Note the use of wxPostEvent (or wxEvtHandler::AddPendingEvent: they're the same) to make communication happen asynchronously, in idle time.

See also http://wiki.wxwidgets.org/Inter-Thread_ ... munication

Regards,

David

Post Reply