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()

-- 
Stephen Kellett
Object Media Limited    http://www.objmedia.demon.co.uk/software.html
Computer Consultancy, Software Development
Windows C++, Java, Assembler, Performance Analysis, Troubleshooting