Reputation: 1869
I am trying to read a string from the ubuntu terminal and set that string as a label of a button. It works perfectly for some iteration and then freezes or closes with error. I couldn't find any pattern about when it freezes or closes. I am using gtk libraries and python 2.7.
A screenshot of the UI after it has frozen can be seen below.
As seen in the above screenshot, it has successfully updated the value 234, 56 and then exited with error after receiving 213 string. You can also observe that the button in the UI also has 213 value.
Sometimes the UI just freezes without displaying any errors or exiting.
I have used the below codes
1. thread.py ( main program called from terminal )
import thread
import time
import gui2
import vkeys1
import os
try:
thread.start_new_thread( vkeys1.main, ( ) )
thread.start_new_thread( gui2.main, ( ) )
except:
print "Error: unable to start thread"
# To stop this script from closing
os.system("mkfifo d1 2> error.log")
fd = os.open('d1', os.O_RDONLY)
ch = os.read(fd,1) # No writer
2. vkeys1.py ( It reads the input from terminal and calls textinit() )
import gui2
def main() :
while True:
try :
gui2.ch = str(input('\nInput a string : '))
gui2.textinit()
except :
print(" \n\n Exception!! \n\n")
3. gui2.py ( Updates the button label )
from gi.repository import Gtk, GdkPixbuf, Gdk, GLib
import Image
import os, sys
import time
import vkeys1
import threading
global ch # ch is used at vkeys1.py to store the input
ch = 'dummy content'
button0 = Gtk.Button(label="Initially empty")
class TableWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="String retrieval widget")
self.set_size_request(500,200)
self.connect_after('destroy', self.destroy)
self.main_box=Gtk.VBox()
self.main_box.set_spacing(5)
self.label = Gtk.Label(" ")
table = Gtk.Table(7,4, True)
self.add(self.main_box)
self.main_box.pack_start(self.label, False, False, 0)
self.main_box.pack_start(table, False, False, 0)
table.attach(button0, 0, 4, 0, 1)
self.show_all()
def destroy(window, self):
Gtk.main_quit()
def textinit(): # called from vkeys1.py
class Thrd(threading.Thread) :
def __init__(self) :
threading.Thread.__init__(self)
print('\nReceived string')
print(str(ch))
print('\n')
button0.set_label(str(ch)) # Button label updated here
Thrd2 = Thrd()
Thrd2.start()
return
def main():
app=TableWindow()
app.set_keep_above(True)
app.set_gravity(Gdk.Gravity.SOUTH_WEST)
Gtk.main()
if __name__ == "__main__":# for any error exit
sys.exit(main())
The above codes can be run by typing python thread.py
(after creating the above 3 files off-course). Please suggest any solution to overcome this freezing problem.
Upvotes: 2
Views: 853
Reputation: 154916
The most likely cause of the crash is that your code invokes GTK code from threads other than the thread that runs the main loop, which the documentation states is not allowed.
To resolve the issue, replace the call of gui2.textinit()
with GLib.idle_add(gui2.textinit)
(note the lack of parentheses after textinit
).
Several remarks about the code:
The generic exception handler is masking exceptions that occur. Remove it, and you will see a useful traceback when something goes wrong.
If you are running under Python 2, you probably want to change input
to raw_input
, otherwise the code chokes on any input that is not a valid Python expression.
textinit
creates a thread object that never runs an actual thread. When inheriting from threading.Thread
, one must override the run
function, which will be invoked in the new thread once start()
is called. Doing the work in the constructor accomplishes nothing.
thread.start_new_thread
is a low-level API that should not be used in normal circumstances and that is demoted to _thread
in Python 3. Instead of thread.start_new_thread(fn, ())
, use threading.Thread(target=fn)
, which has the same meaning, and also returns a Thread
object.
Upvotes: 2