wxListCtrl thread problem

Hi,

I use wxPython on Win2K.

I spawn a single thread that populates a wxListCtrl in my main window.
The main program waits for the thread to finish calling
wxYieldIfNeeded() meanwhile.

Everything works well. After I repeat that procedure a certain number of
times, the application crashes with

Illegal Instruction "0x0100beb9" pointing to memory in "0x03c09fe4". The
procedure READ vould not be processed. (freely translated from german :wink:

This happens always after a certain number of repetitions, depending on
the number of entries I add to the list control. Many entries need less
repetitions then fewer entries.
So something seems to be wrong with the cleanup of the list control ....

I also wrapped my AddList_function into a wxPostEvent() call - but with
the same result.

Any ideas?

All the best,
Harald

Some additional info:
If I use the same function without spawning a thread everything remains
stable.
As soon as I populate the wxListCtrl from a thread, it fails.
Shouldn't wxPostEvent be a thread save method?

Bye,
Harald

Harald Schneider wrote:

Some additional info:
If I use the same function without spawning a thread everything remains
stable.
As soon as I populate the wxListCtrl from a thread, it fails.
Shouldn't wxPostEvent be a thread save method?

Yes.

Can you do it without the wxYieldIfNeeded? Can you reduce it to a small sample?

路路路

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Hello Robin,

thanks for the quick reply.

Can you do it without the wxYieldIfNeeded? Can you reduce it

Yep -- but no success.

to a small
sample?

Here it comes:

query_queue starts a relatively long running thread which collect data
from a mail queue.
Each item collected is added to the wxListCtrl by a callback from the
thread into the main program (maybe this is the prob ???) The struct for
the sorter mixin is build up in parallel.

路路路

-----------------------------
#
# The following stuff is taken from main()
# All things start here.
#
        
    def query_queue(self):
        self.listctrl.Freeze()
        self.listctrl_cnt = 0
        
        self.listctrl_sorter = {}
        self.itemDataMap = self.listctrl_sorter

wxColumnSorterMixin.__init__(self,self.listctrl.GetColumnCount())

        tcnt = threadlib.Counter()
        
        # Starts thread which does a callback for each element
        # added to the list
        #
        # If I do a self.Server.queue.query2(self.listadd),
        # then everything runs stable -- but this blocks my GUI.
        #
        t = TRun(tcnt, self.Server.queue.query2, self.listadd)
        while tcnt.value > 0:
            wxYieldIfNeeded()
            
        self.listctrl.Thaw()

        items = self.listctrl_sorter.items()
        
        for x in range(len(items)):
            key, data = items
            self.listctrl.SetItemData(x,key)
                               
#
# The callback function
# Populates the listcontrol and fillst the
# sorter struct ...
#

    def listadd(self, msg):
        """
        Callback function for self.Server.queue.query2
        """

        # analyze spoolfile and add to listctrl
        #
        if msg.state == 'MESS':
            self.listctrl.InsertImageStringItem(0,' MESS',self.img_mess)
            #self.listctrl.InsertImageItem(0,self.img_mess)
        else:
            if msg.state == 'RSND':
                self.listctrl.InsertImageStringItem(0,'
RSND',self.img_rsnd)
                #self.listctrl.InsertImageItem(0,self.img_rsnd)
            else:
                if msg.state == 'FROZ':
                    self.listctrl.InsertImageStringItem(0,'
FROZ',self.img_froz)
                    #self.listctrl.InsertImageItem(0,self.img_froz)
            
        self.listctrl.SetStringItem(0,1,msg.date)
        self.listctrl.SetStringItem(0,2,msg.evlpfields['mail from'])
        self.listctrl.SetStringItem(0,3,msg.evlpfields['rcpt to'])
        self.listctrl.SetStringItem(0,4,msg.headfields['subject'])
        self.listctrl.SetStringItem(0,5,msg.file)

        # fill sorter struct
        #
        self.listctrl_sorter[self.listctrl_cnt] = [' ' +
                                                  msg.state,
                                                  msg.date,
                                                  msg.evlpfields['mail
from'],
                                                  msg.evlpfields['rcpt
to'],

msg.headfields['subject'],
                                                  msg.file]
        self.listctrl_cnt += 1

#
# This class starts the submitted function in a seperate thread
#
class TRun(threading.Thread):
    def __init__(self, cnt, function, parameter):
        threading.Thread.__init__(self)
        self.cnt = cnt
        self.function = function
        self.parameter = parameter
        self.cnt.inc()
        self.start()
        
    def run(self):
        self.function(self.parameter)
        self.cnt.dec()
-----------------------------

All the best,
Harald

Harald Schneider wrote:

Hello Robin,

thanks for the quick reply.

Can you do it without the wxYieldIfNeeded? Can you reduce it

Yep -- but no success.

to a small sample?

Here it comes:

query_queue starts a relatively long running thread which collect data
from a mail queue.
Each item collected is added to the wxListCtrl by a callback from the
thread into the main program (maybe this is the prob ???)

Yes, because your callback method is still executed in the worker thread. You want it (or at least the parts that add items to the listctrl) to be called from the main (gui) thread. You can see one example of how to do this in the demo, it creates a custom event type and sends events from the worker thread to the gui thread. You can also do something similar without events by using a Queue.Queue and reading items from it in the gui thread in idle time. You can probably also use wxCallAfter to call a function "later" but with the nice side effect that it is called in the context of the gui thread.

In your case you can still execute the data aquisition and processing loop in the thread, but it should use one of the methods above to send each item to the gui thread where it will be added to the listctrl.

If there is still a problem then please send a _fully functional_ (but minimal) that I can just copy/paste/run.

路路路

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!