Why the mutex is not locked

I have a mutex problem, I can’t understand why the part of the code between locking and unlocking is executed simultaneously in all threads. Here is my class:

class MyThread(QtCore.QThread):
    mutex = QtCore.QMutex()
    load_message_input = QtCore.pyqtSignal()

    def __init__(self, id, window):
        super(MyThread, self).__init__()
        self.id = id
        self.window = window

    def run(self):
        print "Thread %d is started" % self.id
        self.get_captcha_value()
        print "Thread %d is finishing" % self.id

    def get_captcha_value(self):
        MyThread.mutex.lock()
        print "Thread %d locks mutex" % self.id
        self.load_message_input.connect(self.window.show_input)
        self.load_message_input.emit()
        self.window.got_message.connect(self.print_message)
        self.window.input_finished.wait(self.mutex)
        print "Thread %d unlocks mutex" % self.id
        MyThread.mutex.unlock()

    @QtCore.pyqtSlot("QString")
    def print_message(self, msg):
        print "Thread %d: %s" % (self.id, msg)

This is how I describe the window:

class MyDialog(QtGui.QDialog):
    got_message = QtCore.pyqtSignal("QString")

    def __init__(self, *args, **kwargs):
        super(MyDialog, self).__init__(*args, **kwargs)
        self.last_message = None

        self.setModal(True)
        self.message_label = QtGui.QLabel(u"Message")
        self.message_input = QtGui.QLineEdit()
        self.dialog_buttons = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel)
        self.dialog_buttons.accepted.connect(self.accept)
        self.dialog_buttons.rejected.connect(self.reject)
        self.hbox = QtGui.QHBoxLayout()
        self.hbox.addWidget(self.message_label)
        self.hbox.addWidget(self.message_input)
        self.vbox = QtGui.QVBoxLayout()
        self.vbox.addLayout(self.hbox)
        self.vbox.addWidget(self.dialog_buttons)
        self.setLayout(self.vbox)

        self.input_finished = QtCore.QWaitCondition()

    @QtCore.pyqtSlot()
    def show_input(self):
        print "showing input"
        self.show()
        self.setModal(True)

    @QtCore.pyqtSlot()
    def on_accepted(self):
        print "emit: ", self.message_input.text()
        self.got_message.emit(self.message_input.text())
        self.input_finished.wakeAll()

And here is the main topic:

import sys
app = QtGui.QApplication(sys.argv)

window = test_qdialog.MyDialog()
threads = []

for i in range(5):
    thread = MyThread(i, window)
    if not thread.isRunning():
        thread.start()
        threads.append(thread)

sys.exit(app.exec_())

The result is as follows:

Thread 0 is startedThread 1 is startedThread 4 is started


Thread 0 locks mutexThread 3 is started
Thread 2 is started

Thread 2 locks mutex
Thread 3 locks mutex
Thread 1 locks mutex
Thread 4 locks mutex
showing input
showing input
showing input
showing input
showing input

UPDATE: Thanks to Joanne for his suggestions. Here's what the code for the MyThread class looks like:

class MyThread(QtCore.QThread):
    mutex = QtCore.QMutex()
    load_message_input = QtCore.pyqtSignal()

    def __init__(self, id, window):
        super(MyThread, self).__init__()
        self.id = id
        self.window = window
        # self.mutex = QtCore.QMutex()
        self.load_message_input.connect(self.window.show_input)

    def run(self):
        print "Thread %d is started" % self.id
        self.get_captcha_value()
        print "Thread %d is finishing" % self.id

    def get_captcha_value(self):
        MyThread.mutex.lock()
        print "Thread %d locks mutex" % self.id
        self.load_message_input.emit()
        mutex2 = QtCore.QMutex()
        mutex2.lock()
        self.window.got_message.connect(self.print_message)
        self.window.input_finished.wait(mutex2)
        mutex2.unlock()
        self.window.got_message.disconnect(self.print_message)
        print "Thread %d unlocks mutex" % self.id
        MyThread.mutex.unlock()

    @QtCore.pyqtSlot("QString")
    def print_message(self, msg):
        print "Thread %d: %s" % (self.id, msg)

Now I get this this exception after the completion of the first thread:

Traceback (most recent call last):
  File "/path/to/script/qdialog_threads.py", line 20, in run
    self.get_captcha_value()
  File "path/to/script/qdialog_threads.py", line 34, in get_captcha_value
    MyThread.mutex.unlock()
AttributeError: 'NoneType' object has no attribute 'mutex'
+3
source share
2 answers

You do not flush the buffers in your calls print. Also keep in mind that output is showing inputgenerated in the GUI thread, so this can happen anytime after the mutex is locked - including after the mutex is already unlocked.

0

, ( with - , ):

# Lock declaration
CONSOLELOCK = threading.Lock()

# Then for any print
with CONSOLELOCK:
    print("Anything")

, , , .

,

self.window.input_finished.wait(self.mutex), , . , , , load_message, _ . , , load_message ( ). , . self.window.input_finished.wait(self.mutex2).

, on_accepted , window.got_message, .

0

All Articles