lst = [1, 2, 3, 4, 5, 6, 7, 8, 9]
class Thread(QRunnable):
def __init__(self):
super(Thread, self).__init__()
self.mutex = QMutex()
def run(self):
self.mutex.lock()
lst.pop(0)
print(str(lst))
time.sleep(5)
self.mutex.unlock()
The code above is an example of what I am trying to acheive, I have a list that is defined outside the class. I want to periodically pop the first element of the list. If I am running 5 threads I only want one thread to mutate the list at single time. Everytime I try this the 5 threads all try to pop the first element and dont wait as I want. When I recreate this in the native python threading library, it works as intended. What am I doing wrong here?
CodePudding user response:
The problem is that you create a mutex per thread. A mutex lock only protects from threads using the same mutex. Since each thread is using its own private lock, its only protected from itself. Expanding on @eyllanesc answer, I've created a single mutex for all threads to use. The mutex should be considered associated with the data it protects.
import sys
import time
from PyQt6.QtCore import QCoreApplication, QMutex, QRunnable, QThreadPool, QTimer
# data with mutex access controls
mutex = QMutex()
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9]
class Thread(QRunnable):
def run(self):
#mutex = QMutex() <-- don't create a private mutex
mutex.lock()
lst.pop(0)
print(lst, time.time()-start, flush=True)
time.sleep(5)
mutex.unlock()
start = time.time()
def main():
app = QCoreApplication(sys.argv)
QTimer.singleShot(8 * 1000, QCoreApplication.quit)
pool = QThreadPool()
for i in range(5):
runnable = Thread()
pool.start(runnable)
sys.exit(app.exec())
if __name__ == "__main__":
main()