Solved QMutexLocker in Q_PROPERTY READ/WRITE methods blocks execution
-
Recommends does not mean mandate.
If your setter would not emit a signal, then QMutexLocker is the right tool. Since you are emitting a signal, standard mutex manipulation applies or this could be an alternative:void QGUI::setIpv4(QString value) { bool mustEmit(false); { // new scope QMutexLocker locker(&mutex_); if (m_ipv4 != value) { m_ipv4 = value; mustEmit = true; } } // locker is destroyed if (mustEmit) { ipv4Changed(); } }
As for the shortest path, as above you don't need to create the locker on the top of the method but on the top of the scope where you will access the variable you want to protect.
-
@prex said in QMutexLocker in Q_PROPERTY READ/WRITE methods blocks execution:
If you're wondering why I'm using the QMutexLockers: We're running a near real-time application in another QThread. I don't want to run the Qt execution loop there, but I still need to access the Q_Properties of the main/GUI thread. I found using a mutex in the getter/setter functions and directly accessing them from the other thread really neat. Do you see any better solution?
Is the datum underlying the property atomic, or otherwise guaranteed by the target platform guaranteed to be consistently accessed across threads? Using a mutex in one thread and not in the other doesn't appear to buy anything useful.
-
@SGaist said in QMutexLocker in Q_PROPERTY READ/WRITE methods blocks execution:
void QGUI::setIpv4(QString value) { bool mustEmit(false); { // new scope QMutexLocker locker(&mutex_); if (m_ipv4 != value) { m_ipv4 = value; mustEmit = true; } } // locker is destroyed if (mustEmit) { ipv4Changed(); } }
This could be simplified a bit more, and demonstrate the ability of QMutexLocker or any RAII construct to handle multiple paths without additional user code:
> void QGUI::setIpv4(QString value) { { // new scope QMutexLocker locker(&mutex_); if (m_ipv4 == value) return; // locker is destroyed, mutex_ released m_ipv4 = value; } // locker is destroyed, mutex_ released emit ipv4Changed(); }
-
@prex said in QMutexLocker in Q_PROPERTY READ/WRITE methods blocks execution:
But what you propose requires an execution loop in my thread. I'm not concerned about the minimal lag in the GUI, I just don't want to run the execution loop in the thread, since I'm running a while loop with a fixed timing.
Only in the receiving thread, to my knowledge. That would be the GUI thread, and I assume you are running an event loop there (I doubt UI would work otherwise).
-
@SGaist said in QMutexLocker in Q_PROPERTY READ/WRITE methods blocks execution:
Recommends does not mean mandate.
If your setter would not emit a signal, then QMutexLocker is the right tool. Since you are emitting a signal, standard mutex manipulation applies or this could be an alternative:void QGUI::setIpv4(QString value) { bool mustEmit(false); { // new scope QMutexLocker locker(&mutex_); if (m_ipv4 != value) { m_ipv4 = value; mustEmit = true; } } // locker is destroyed if (mustEmit) { ipv4Changed(); } }
As for the shortest path, as above you don't need to create the locker on the top of the method but on the top of the scope where you will access the variable you want to protect.
Thanks, this makes sense.
@jeremy_k said in QMutexLocker in Q_PROPERTY READ/WRITE methods blocks execution:
@prex said in QMutexLocker in Q_PROPERTY READ/WRITE methods blocks execution:
If you're wondering why I'm using the QMutexLockers: We're running a near real-time application in another QThread. I don't want to run the Qt execution loop there, but I still need to access the Q_Properties of the main/GUI thread. I found using a mutex in the getter/setter functions and directly accessing them from the other thread really neat. Do you see any better solution?
Is the datum underlying the property atomic, or otherwise guaranteed by the target platform guaranteed to be consistently accessed across threads? Using a mutex in one thread and not in the other doesn't appear to buy anything useful.
Not sure if I understand. But both threads use the same mutex since they both call the getter/setter method. One over properties, one directly by calling the method.
@jeremy_k said in QMutexLocker in Q_PROPERTY READ/WRITE methods blocks execution:
@SGaist said in QMutexLocker in Q_PROPERTY READ/WRITE methods blocks execution:
void QGUI::setIpv4(QString value) { bool mustEmit(false); { // new scope QMutexLocker locker(&mutex_); if (m_ipv4 != value) { m_ipv4 = value; mustEmit = true; } } // locker is destroyed if (mustEmit) { ipv4Changed(); } }
This could be simplified a bit more, and demonstrate the ability of QMutexLocker or any RAII construct to handle multiple paths without additional user code:
> void QGUI::setIpv4(QString value) { { // new scope QMutexLocker locker(&mutex_); if (m_ipv4 == value) return; // locker is destroyed, mutex_ released m_ipv4 = value; } // locker is destroyed, mutex_ released emit ipv4Changed(); }
But this would emit signals even if the value did not change and if I understand correctly, this is not good practice.
@Asperamanca said in QMutexLocker in Q_PROPERTY READ/WRITE methods blocks execution:
@prex said in QMutexLocker in Q_PROPERTY READ/WRITE methods blocks execution:
But what you propose requires an execution loop in my thread. I'm not concerned about the minimal lag in the GUI, I just don't want to run the execution loop in the thread, since I'm running a while loop with a fixed timing.
Only in the receiving thread, to my knowledge. That would be the GUI thread, and I assume you are running an event loop there (I doubt UI would work otherwise).
Indeed, the receiving thread/main thread/GUI thread runs an execution loop. But I think to use slots in the workerThread (the one that shouldn't have an execution loop), I would need an execution loop (since no direct connection across threads).
-
@prex said in QMutexLocker in Q_PROPERTY READ/WRITE methods blocks execution:
But this would emit signals even if the value did not change and if I understand correctly, this is not good practice.
How do you figure it would emit if unchanged value given that code has:
if (m_ipv4 == value) return;
?
-
@JonB said in QMutexLocker in Q_PROPERTY READ/WRITE methods blocks execution:
@prex said in QMutexLocker in Q_PROPERTY READ/WRITE methods blocks execution:
But this would emit signals even if the value did not change and if I understand correctly, this is not good practice.
How do you figure it would emit if unchanged value given that code has:
if (m_ipv4 == value) return;
?
Whoops, missed that line.
-
@jeremy_k even better ! I knew I was missing something in my implementation.
-
@SGaist Never go first in code golf!
-
@prex said in [QMutexLocker in Q_PROPERTY READ/WRITE methods blocks execution](/post
Is the datum underlying the property atomic, or otherwise guaranteed by the target platform guaranteed to be consistently accessed across threads? Using a mutex in one thread and not in the other doesn't appear to buy anything useful.
Not sure if I understand. But both threads use the same mutex since they both call the getter/setter method. One over properties, one directly by calling the method.
I wasn't sure if "directly accessing them" meant the getter and setter functions, or the datum. Since it's now clear that it refers to the functions, that implies access to the QObject instance. In that case, be aware that very few of QObject's functions are thread-safe.