4

I'm creating GUI using gtk3. So that the GUI and operation works together, I make a thread with this code: threading.Thread(target=function).start(). Without threading, everything works well, but the GUI will be freezed. With threading, this error occured:

The first one is Segmentation fault (core dumped)

The second one is *** glibc detected *** python: double free or corruption (!prev): 0x09154320 ***

The third one is Gtk:ERROR:/build/buildd/gtk+3.0-3.4.2/./gtk/gtktextview.c:3726:gtk_text_view_va‌​lidate_onscreen: assertion failed: (priv->onscreen_validated) Aborted (core dumped)

Do you know why did that happens?

EDIT: my code:

GUI.py

from gi.repository import Gtk, Gdk, GLib
import Process
import gobject
import threading

class gui():
def __init__(self):
    self.window = Gtk.Window()
    self.window.connect('delete-event', Gtk.main_quit)

    self.box = Gtk.Box()
    self.window.add(self.box)

    self.label = Gtk.Label('idle')
    self.box.pack_start(self.label, True, True, 0)

    self.progressbar = Gtk.ProgressBar()
    self.box.pack_start(self.progressbar, True, True, 0)

    self.button = Gtk.Button(label='Start')
    self.button.connect('clicked', self.on_button_clicked)
    self.box.pack_start(self.button, True, True, 0)

    self.window.show_all()

    GLib.threads_init()
    Gdk.threads_init()
    Gdk.threads_enter()
    Gtk.main()
    Gdk.threads_leave()

def working1(self):
   self.label.set_text('working1')
   result = Process.heavyworks1()   
   print result
   self.label.set_text('idle')  

def on_button_clicked(self, widget):
    threading.Thread(target=self.working1).start()

if __name__ == '__main__':
    gui = gui()

gui

Process.py

a = 0 x = 'something'

def heavyworks1():
    #global a
    #doing something
    #doing other thing
    #a = something
    #return result

def heavyworks2(param):
     #doing something
    #doing other thing
    #return result
Glorfindel
  • 21,988
  • 13
  • 81
  • 109
user2435611
  • 1,093
  • 1
  • 12
  • 18
  • 2
    Are you trying to access Gtk+ objects from multiple threads? Most GUI libraries don't allow that. – abarnert Jun 05 '13 at 19:08
  • 1
    Also, are you trying to access any shared mutable objects from multiple threads without locks or other synchronization? You _often_ get away with that in Python because of the GIL, but not always. And, unless you actually know the rules for when you fall into that "often" and when you "don't", you should always play it safe. – abarnert Jun 05 '13 at 19:09
  • Anyway, if you want more than vague hints, you will have to show us actual code. Post a [SSCCE](http://sscce.org) that contains just enough of your code to demonstrate the problem, and then people can read it or even debug it, instead of guessing. – abarnert Jun 05 '13 at 19:10
  • it's always a bit tricky when it comes to threading and GUIs. Sometimes the GUI-Libs provide their own threading...have you checked the gtk3 docs for something like that? – pypat Jun 05 '13 at 19:28
  • maybe this is of help: http://stackoverflow.com/questions/11923008/threading-in-gtk-python – pypat Jun 05 '13 at 19:29
  • @BRnert: yes, I'm accesing gtk from thread so that my gui won't freeze. @pypat: many materials about gtk threading in internet just tell something like `gobject.idle_add()` and `threads_init(), threads_enter(), threads_leave()` for accessing gui – user2435611 Jun 06 '13 at 02:34
  • @user2435611 if i had knwn about those i would have told you -.- – pypat Jun 06 '13 at 06:56
  • Don't access GTK from multiple threads. (And `threads_enter` makes no sense when used for the whole main loop.) The correct way to approach this is outlined in my [answer to your other question](http://stackoverflow.com/a/16949065/1600898). – user4815162342 Jun 06 '13 at 11:50
  • Also, you're supposed to call `GLib.threads_init` and `Gtk.threads_init` **before** making any glib/gtk calls. Move those calls immediately after the respective imports of `GLib` and `Gtk`. – user4815162342 Jun 07 '13 at 07:24
  • I think i already know why. As abarnert and user4815162342 said, there's still my code that accesing gtk from thread :p – user2435611 Jun 07 '13 at 11:20

2 Answers2

7

I've resolved this one. What you need to do is FULLY SEPARATE ANY GTK CALL FROM ANY THREAD.

Those error occured because there were still some code accessing gtk ui from worker thread (thread that doing my calculation in the background). What I need to do is just separate ALL gtk call from thread by using gobject.idle_add(some_fuction_telling_gtk_what_to_do)

This is a sample:

def stop_progress(self):
    self.worker.join()
    self.label.set_text('idle') 

def working_thread(self, num):
    self.textview.set_text(num)
    Process.heavyworks2(num)    
    gobject.idle_add(self.stop_progress)

self.worker = threading.Thread(target=self.working_thread, args=[100000])
self.worker.start()

You see from that code a function that suppose to working in the background (working_thread(self,num)) still having a line accessing gtk call (self.textview.set_text(num)). Separate that code into a function and call it from your thread using gobject.idle_add(gtk_call_function).

It's become like this.

def stop_progress(self):
    self.worker.join()
    self.label.set_text('idle') 

def updateTextView(self, num):
    self.textview.set_text(num)     

def working_thread(self, num):
    gobject.idle_add(self.updateTextView, num)
    Process.heavyworks2(num)    
    gobject.idle_add(self.stop_progress)

self.worker = threading.Thread(target=self.working_thread, args=[100000])
self.worker.start()

So, one important point here is don't update gtk ui directly from any thread. Just separate every code accessing gtk into a function and call it by gobject.idle_add() from thread.

user2435611
  • 1,093
  • 1
  • 12
  • 18
1

Perhaps you have to do this first:

import gobject
gobject.threads_init()

Does that keep it from crashing? (Check out http://faq.pygtk.org/index.py?req=show&file=faq20.006.htp)

Velimir Mlaker
  • 10,664
  • 4
  • 46
  • 58