S
Stephen Kellett
Hello everyone,
I've been trying to write a trivial multi-threaded application that has
a GUI (implemented using TkRuby) and which updates various counters on
the GUI. Problem is it deadlocks as soon as I try to update the
graphical part, but I am unsure why. I've included the most stripped
down version of the code here - which will not deadlock - it will just
output to stdout. If you comment in the two obvious lines (commented to
indicate which ones) then it does deadlock.
Am I doing something wrong?
Have I made incorrect assumptions?
How should I do this?
Is it possible to update Tk components from threads other than the main
GUI thread?
Cheers
Stephen
require 'tk' # get widget classes
require 'thread'
class RTVExample < TkRoot
def initialize(args)
super(args)
@countA = 0
@countB = 0
@lock1 = Mutex.new
# create our UI
@menubar = TkMenubar.new(nil, nil)
@menubar.pack('side'=>'top', 'fill'=>'x')
@menubar.add_menu([['File', 0],
['Exit', proc{exitFunc}, 0]])
@menubar.add_menu([['Thread Test', 0],
['Test 1', proc{testThread1}, 0]])
@counterLabel = TkLabel.new{text 'Counter' ; pack {padx=30 ; pady=0}}
end
# why does this deadlock? - surely it should just run the two threads alongside the GUI thread.
def testThread1()
# create two the threads - comment in the #@counter lines to see the deadlock
tok1 = Thread.new do
10000.times {
@lock1.synchronize { @countA += 1 }
puts "A:" + @countA.to_s()
# this next line causes the deadlock - why?
#@counterLabel.configure(text=>"Counter A: %d" % @countA)
}
end
tok2 = Thread.new do
10000.times {
@lock1.synchronize { @countB += 1 }
puts "B:" + @countB.to_s()
# this next line causes the deadlock - why?
#@counterLabel.configure(text=>"Counter B: %d" % @countB)
}
end
tok1.join
tok2.join
end
def exitFunc()
TkRoot.destroy()
end
end
# run the GUI app
gui = RTVExample.new()
Tk.mainloop()
I've been trying to write a trivial multi-threaded application that has
a GUI (implemented using TkRuby) and which updates various counters on
the GUI. Problem is it deadlocks as soon as I try to update the
graphical part, but I am unsure why. I've included the most stripped
down version of the code here - which will not deadlock - it will just
output to stdout. If you comment in the two obvious lines (commented to
indicate which ones) then it does deadlock.
Am I doing something wrong?
Have I made incorrect assumptions?
How should I do this?
Is it possible to update Tk components from threads other than the main
GUI thread?
Cheers
Stephen
require 'tk' # get widget classes
require 'thread'
class RTVExample < TkRoot
def initialize(args)
super(args)
@countA = 0
@countB = 0
@lock1 = Mutex.new
# create our UI
@menubar = TkMenubar.new(nil, nil)
@menubar.pack('side'=>'top', 'fill'=>'x')
@menubar.add_menu([['File', 0],
['Exit', proc{exitFunc}, 0]])
@menubar.add_menu([['Thread Test', 0],
['Test 1', proc{testThread1}, 0]])
@counterLabel = TkLabel.new{text 'Counter' ; pack {padx=30 ; pady=0}}
end
# why does this deadlock? - surely it should just run the two threads alongside the GUI thread.
def testThread1()
# create two the threads - comment in the #@counter lines to see the deadlock
tok1 = Thread.new do
10000.times {
@lock1.synchronize { @countA += 1 }
puts "A:" + @countA.to_s()
# this next line causes the deadlock - why?
#@counterLabel.configure(text=>"Counter A: %d" % @countA)
}
end
tok2 = Thread.new do
10000.times {
@lock1.synchronize { @countB += 1 }
puts "B:" + @countB.to_s()
# this next line causes the deadlock - why?
#@counterLabel.configure(text=>"Counter B: %d" % @countB)
}
end
tok1.join
tok2.join
end
def exitFunc()
TkRoot.destroy()
end
end
# run the GUI app
gui = RTVExample.new()
Tk.mainloop()