Hi all, I'm working on a (Python) program which, in short, is a threaded TCP socket server which creates a new "tab" in a wx.Notebook widget for every incoming connection it sees. I've run into a strange problem where when I call notebook.AddPage(...), one of three things happens:

  1. A "tab" correctly appears for the new page
  2. No new "tab" appears, even though if I call GetPageCount() on the notebook, it returns the correct value
  3. I receive the following error: "*** glibc detected *** python: double free or corruption (fasttop): 0x000000000164dbe0 ****" followed by a very long backtrace with a cryptic memory map.

Since it would be inconsiderate to post all of my code here, I wrote a little script (based on something I found online) which also exhibits this behavior (although it works correctly most of the time).

import wx
from wx.lib.pubsub import Publisher
import thread
import time

# Some classes to use for the notebook pages.  Obviously you would
# want to use something more meaningful for your application, these
# are just for illustration.

class PageOne(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        t = wx.StaticText(self, -1, "This is a PageOne object", (20,20))

class PageTwo(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        t = wx.StaticText(self, -1, "This is a PageTwo object", (40,40))

class PageThree(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        t = wx.StaticText(self, -1, "This is a PageThree object", (60,60))


class MainFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, title="Simple Notebook Example", size=(600, 500))
        Publisher.subscribe(self.NewPage, "add.page")

        # Here we create a panel and a notebook on the panel
        panel = wx.Panel(self)
        self.notebook = wx.Notebook(panel)

        # create the page windows as children of the notebook
        page1 = PageOne(self.notebook)
        page2 = PageTwo(self.notebook)
        page3 = PageThree(self.notebook)

        # add the pages to the notebook with the label to show on the tab
        self.notebook.AddPage(page1, "Main")

        # finally, put the notebook in a sizer for the panel to manage
        # the layout
        sizer = wx.BoxSizer()
        sizer.Add(self.notebook, 1, wx.EXPAND)
        panel.SetSizer(sizer)

    def NewPage(self, msg):
        name = msg.data
        page = PageOne(self.notebook)
        self.notebook.AddPage(page, name)
        print "Added page with name: '" + name + "'."


def delayedPageAdd():
    n = 1
    while n < 10:
        time.sleep(1)
        Publisher.sendMessage("add.page", ("Page%d" % n))
        n += 1

if __name__ == "__main__":
    app = wx.App()
    MainFrame().Show()
    thread.start_new_thread(delayedPageAdd, ())
    app.MainLoop()

In summary, this code creates a wx.Notebook widget and then spawns off a thread that creates a new tab/page every second and adds it to the notebook.

Thank you so much in advance if anybody has any idea what is going on.

Gribouillis commented: An exemplar of well written post +13

Dani AI

Generated

Short summary: the behavior you saw (sometimes no tab, sometimes a crash including "double free or corruption") is a classic symptom of doing wx GUI work from a background thread. As discovered, moving the UI call back onto the main thread (the fix suggested — a thread-safe decorator) eliminated the problem.

Why this happens: most native GUI toolkits require widgets to be created and modified on the GUI/main thread. Calling AddPage or creating panels from a worker thread can race with the toolkit's C-level code and corrupt memory, which shows up as intermittent failures or native crashes.

Practical fixes (safe and simple):

  • Schedule UI work on the main thread with wx.CallAfter. For example, have the worker thread signal the main thread and call a helper that creates the page and calls AddPage. Do not create the page object in the worker thread — create and add it on the main thread.
  • Alternatively post a custom wx event with wx.PostEvent and handle it in the frame, or use a library/decorator that marshals calls to the GUI thread (what recommended).
  • Prefer threading.Thread (daemon if appropriate) rather than the old thread module.

Quick checklist if tabs still do not appear or you see odd behavior:

  • Make sure both creation of the panel and AddPage run on the main thread (scheduling only AddPage while creating the widget in a worker thread is not safe).
  • After adding a page, call Layout() on the parent or Refresh()/Update() on the notebook if visuals are stale.
  • If crashes persist, isolate whether the worker thread makes any other native calls; fix by marshaling all native/GUI interactions to the main thread.

This approach preserves responsiveness while avoiding the intermittent, hard-to-reproduce corruption you experienced.

Recommended Answers

All 3 Replies

Percect! Thank you so much Gribouillis! The decorator worked perfectly - apparently it was a problem with thread safety.

Thanks again!

Great! A good link to keep :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.