Search code examples
pythonmultithreadingqtpysidecx-freeze

QThread blocks in decoding UTF-16 when python code is freezed by cx_Freeze?


In fact, the problem is a serious bug in a huge system, and we simplifiy the problem into code snippet below. We wanna figure out why the thread behaviors are different in python code and exe file.

The code includes two threads, and we expect both the two threads could run simutaneously and terminate in Windows 7 (64 bit) with python 2.7.

The code runs correctly when I use CPython directly, say, using "python tThread.py" in console. Both the two threads run and finish normally.

However, when the code is freezed into exe with cx_Freeze 5.0.1 and executed, the sub-thread blocks in the line uu = u16.decode("utf-16") , while the main thread goes into dead loop.

Below is tThread.py :

# -*- coding: UTF-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')  

import time
from PySide import QtGui, QtCore
from PySide.QtCore import *
from PySide.QtGui import *

class Worker(QObject):
    done = QtCore.Signal()
    def longRun(self):
        count = 1
        while count < 20:
            print "Worker Thread", count
            u16 = u"ABCD".encode("utf-16")
            uu = u16.decode("utf-16")     # Block here <---
            count += 1
        self.done.emit()


def mainThread():
    app = QApplication([])

    objThread = QThread()
    obj = Worker()
    obj.moveToThread(objThread)
    obj.done.connect(objThread.quit)
    objThread.started.connect(obj.longRun)
    objThread.start()


    i = 1
    while not objThread.isFinished():
        QCoreApplication.processEvents()
        print "Main Thread", i
        time.sleep(0.1)
        i+=1

    print "Main Thread Over"

mainThread()
sys.exit()

Below is the setup.py file for cx_Freeze :

(console command is "python setup.py build_exe -b build")

from cx_Freeze import setup, Executable
import platform

build_exe_options = {
    "packages": [ "PySide"],
    "include_msvcr": True
};

exe = Executable(u".\\tThread.py", base=None, targetName="tThread.exe" )

setup(  name = "tThread",
        version = "0.1",
        description = u"tThread",
        options = {"build_exe": build_exe_options},
        executables = [exe])

We suspect that there is bug in cx_Freeze, which leads to the different behaviors between raw code and exe . Please help us find solution to make the thread pass the decode code, thanks.


After difficult debugging for several days, we find the thread blocks in this line in $Python27$\Lib\encodings\__init__.py

    mod = __import__('encodings.' + modname, fromlist=_import_tail,level=0)

cx_Freeze has a bug for runtime module-import in multi-threading.


Finally, we bypass the blocking code using hack-code, say, manually import the modules outside the thread code. However, we do not think it is an elegant solution since there is still hidden import bug which may happen in future. Hopes that the author of cx_Freeze can fix the bug and provide the perfect solution to our question.


Solution

  • The author of cx_Freeze has solved the bug and update it to 5.0.2 .

    The related issue is Here