1

There is something weird in my code, that I couldn't find a solution for anywhere online (at least I tried).

The code runs perfectly on 1 thread.

for i in range(1):

When I try and increase the thread count,

for i in range(3):

the code stops running correctly ( The captcha GUI stops showing with no error, simply stops showing )

What I'm trying to do, is pop a captcha using tkinter GUI for the user to solve.

This is a very simplified version off my code, simply for this post.

import requests,cStringIO, PIL , Queue
from Functions import *
from PIL import ImageTk
import Tkinter as tk
from Tkinter import *
import threading

__author__ = 'user'
Session = {'view_state': '', 'event_validation': ''}
threadLock = threading.Lock()

class PopCaptcha( Frame  ):
    def __init__( self , img):

        def onok(event=None):
            self.captchaText = self.entry1.get()
            self.captchaThread = 1
            self.master.destroy()

        self.captchaThread = 0
        self.captchaText = ""
        tk.Frame.__init__(self)

        self.pack()
        self.master.title("Enter Captcha")

        image1 = PIL.Image.open(img)
        tkpi = ImageTk.PhotoImage(image1)

        self.picture1 = Label(self, image=tkpi)
        self.picture1.image = tkpi
        self.picture1.grid(row= 1)

        self.entry1 = Entry(self , font=('Helvetica', '14'))
        self.entry1.grid(row= 2)

        self.button1 = Button( self, text = "SUBMIT", width = 25,
                               command = onok )
        self.button1.grid( row = 3)

        self.master.bind('<Return>', onok)
        self.master.protocol("WM_DELETE_WINDOW", self.on_closing)


    def on_closing(self):
        self.captchaThread = 1
        self.master.destroy()




class TestClass:
    def __init__(self):
        self.error = ""
        self.status = ""
        self.captchaTries = 0

    def DoThing(self):
        self.status = ""
        self.error = ""
        self.captchaThread = 0

        captchaurl = "https://upload.wikimedia.org/wikipedia/commons/6/69/Captcha.jpg"


        hr = requests.get(captchaurl)
        captchafile = cStringIO.StringIO(hr.content)

        while self.status is not "OK" or self.error == "WrongCaptcha":
            self.captchaTries += 1

            if (self.captchaTries > 3):
                hr = requests.get(captchaurl)
                captchafile = cStringIO.StringIO(hr.content)
                self.captchaTries = 0



            print "Preparing Captcha..."
            threadLock.acquire()
            captcha = PopCaptcha(captchafile)
            print "Showing Captcha..."
            captcha.mainloop()
            print "Captcha Showen"
            threadLock.release()


            while captcha.captchaThread == 0:
                pass


            Session['Captcha'] = captcha.captchaText

            PostData = {
                'Captcha' : Session['Captcha']
            }

            headers = {
                'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:39.0) Gecko/20100101 Firefox/39.0',
                'X-Requested-With': 'XMLHttpRequest',
                'X-MicrosoftAjax' : 'Delta=true',
                'Pragma' : 'no-cache',
                'content-type': 'application/x-www-form-urlencoded; charset=utf-8',
                'Accept' : 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                'Accept-Charset' : 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
                'Accept-Language' : 'en-US,en;q=0.5'
            }

            print "Attempting to post ..."
            r = requests.post("http://google.com", data=PostData, headers=headers)

            if 1:
                print "FAILED"
                self.error = "WrongCaptcha"
            else:
                print "WORKED"
                self.error = "NoError"
                self.status = "OK"


print "Welcome to MD5 Cracker!"
threads = []


for i in range(3):
    hk = TestClass()
    t = threading.Thread(target=hk.DoThing)
    threads.append(t)

for x in threads:
    x.start()
    print "Thread started"

Is there anything wrong with my code that I'm not aware off ? How this issue can be solved ?

Thanks

Lambasoft
  • 909
  • 2
  • 14
  • 33

1 Answers1

2

Tkinter isn't thread safe. You are trying to create widgets in multiple threads, which rarely works.

It might be possible to create separate root windows in each thread, but I've never tried such a thing. You can probably do this without threads, but it's hard to understand why you're creating widgets for each thread.

Normally in a multithreaded tkinter app, you have a single thread that contains the widgets, and then the other threads do the data processing and put changes on a queue that the GUI thread reads from to update its display.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Do you have a source for the statement that Tkinter is not thread safe? – steffen Dec 15 '16 at 00:42
  • 1
    @steffen: I don't have a 100% definitive source (ie: there's no statement in the tkinter or tk docs that say "tkinter isn't thread safe"). However, Donal Fellows is one of the core maintainers of the tcl/tk project (upon which tkinter is built) and he had a pretty good explanation of the situation here: http://stackoverflow.com/a/38767665/7432. If Donal isn't _the_ most authoritative source of information, he's in the top two or three. – Bryan Oakley Dec 15 '16 at 02:28