QTimer::singleShot()'s syntax
-
Your threading is all jumbled up, you can't just read and modify fields from objects that are in different threads ... if it works, it's the hand of god, if it doesn't work, it's the hand of god as well ... (and that one comes from an atheist)
To give you a straightforwardly obvious example:
https://github.com/opencor/opencor/blob/master/src/plugins/support/SimulationSupport/src/simulationworker.cpp#L95What's guarding
mCurrentPoint
?
I would also imagine you may get a lot of runtime warnings from Qt about objects being created beforeQApplication
(due to singletons) and possibly also warnings about destruction order or destructions from different threads.@kshegunov: yes, I think it's starting to become very clear that I am facing a race condition and that I have been pretty lucky these past few years. Ok, I guess I am going to have to check that very carefully. (In the end, it's a good thing that I decided to use the new syntax... (Positive thinking... :))
-
Your threading is all jumbled up, you can't just read and modify fields from objects that are in different threads ... if it works, it's the hand of god, if it doesn't work, it's the hand of god as well ... (and that one comes from an atheist)
To give you a straightforwardly obvious example:
https://github.com/opencor/opencor/blob/master/src/plugins/support/SimulationSupport/src/simulationworker.cpp#L95What's guarding
mCurrentPoint
?
I would also imagine you may get a lot of runtime warnings from Qt about objects being created beforeQApplication
(due to singletons) and possibly also warnings about destruction order or destructions from different threads.@kshegunov: by the way, no, I am not getting any runtime warnings from Qt.
-
@kshegunov: by the way, no, I am not getting any runtime warnings from Qt.
a race condition
More than one, I noticed at least several in that particular file.
by the way, no, I am not getting any runtime warnings from Qt.
I said you may, not that you are going to, as I didn't check the whole source. I spotted a place or two where you use the singleton, so that's usually accompanied by such warnings.
-
a race condition
More than one, I noticed at least several in that particular file.
by the way, no, I am not getting any runtime warnings from Qt.
I said you may, not that you are going to, as I didn't check the whole source. I spotted a place or two where you use the singleton, so that's usually accompanied by such warnings.
@kshegunov said in QTimer::singleShot()'s syntax:
a race condition
More than one, I noticed at least several in that particular file.
Would you mind letting me know (via MP, if you want) those you noticed?
by the way, no, I am not getting any runtime warnings from Qt.
I said you may, not that you are going to, as I didn't check the whole source. I spotted a place or two where you use the singleton, so that's usually accompanied by such warnings.
Yes, I know what you said. I was merely pointing out that, in my particular case, I am not getting runtime warnings.
Otherwise, when it comes to my singletons, I believe they are always used in the main thread. This being said, I am going to double check and also make sure that they are thread safe. So, thanks for the reminder.
-
@kshegunov said in QTimer::singleShot()'s syntax:
a race condition
More than one, I noticed at least several in that particular file.
Would you mind letting me know (via MP, if you want) those you noticed?
by the way, no, I am not getting any runtime warnings from Qt.
I said you may, not that you are going to, as I didn't check the whole source. I spotted a place or two where you use the singleton, so that's usually accompanied by such warnings.
Yes, I know what you said. I was merely pointing out that, in my particular case, I am not getting runtime warnings.
Otherwise, when it comes to my singletons, I believe they are always used in the main thread. This being said, I am going to double check and also make sure that they are thread safe. So, thanks for the reminder.
@agarny said in QTimer::singleShot()'s syntax:
https://github.com/opencor/opencor/blob/master/src/plugins/support/SimulationSupport/src/simulationworker.cpp#L207
https://github.com/opencor/opencor/blob/master/src/plugins/support/SimulationSupport/src/simulationworker.cpp#L214
https://github.com/opencor/opencor/blob/master/src/plugins/support/SimulationSupport/src/simulationworker.cpp#L215
https://github.com/opencor/opencor/blob/master/src/plugins/support/SimulationSupport/src/simulationworker.cpp#L217
https://github.com/opencor/opencor/blob/master/src/plugins/support/SimulationSupport/src/simulationworker.cpp#L235
https://github.com/opencor/opencor/blob/master/src/plugins/support/SimulationSupport/src/simulationworker.cpp#L236
https://github.com/opencor/opencor/blob/master/src/plugins/support/SimulationSupport/src/simulationworker.cpp#L237
https://github.com/opencor/opencor/blob/master/src/plugins/support/SimulationSupport/src/simulationworker.cpp#L244And so on ... the list is very, very long.
As far as I could see only the
SimulationWorker
object is moved to a separate thread, so you should focus your efforts there. For one don't pass it objects that are in different threads (e.g.Simulation
class'smSimulation
), as it gets quite alluring to just call methods on them (which is a race condition). Instead, move the setters ofSimulationWorker
as slots and emit signals when any of the private/calculated data has changed. Then you can connect those signals and slots from the outside and Qt will take care of the access serialization for you. -
@agarny said in QTimer::singleShot()'s syntax:
https://github.com/opencor/opencor/blob/master/src/plugins/support/SimulationSupport/src/simulationworker.cpp#L207
https://github.com/opencor/opencor/blob/master/src/plugins/support/SimulationSupport/src/simulationworker.cpp#L214
https://github.com/opencor/opencor/blob/master/src/plugins/support/SimulationSupport/src/simulationworker.cpp#L215
https://github.com/opencor/opencor/blob/master/src/plugins/support/SimulationSupport/src/simulationworker.cpp#L217
https://github.com/opencor/opencor/blob/master/src/plugins/support/SimulationSupport/src/simulationworker.cpp#L235
https://github.com/opencor/opencor/blob/master/src/plugins/support/SimulationSupport/src/simulationworker.cpp#L236
https://github.com/opencor/opencor/blob/master/src/plugins/support/SimulationSupport/src/simulationworker.cpp#L237
https://github.com/opencor/opencor/blob/master/src/plugins/support/SimulationSupport/src/simulationworker.cpp#L244And so on ... the list is very, very long.
As far as I could see only the
SimulationWorker
object is moved to a separate thread, so you should focus your efforts there. For one don't pass it objects that are in different threads (e.g.Simulation
class'smSimulation
), as it gets quite alluring to just call methods on them (which is a race condition). Instead, move the setters ofSimulationWorker
as slots and emit signals when any of the private/calculated data has changed. Then you can connect those signals and slots from the outside and Qt will take care of the access serialization for you.@kshegunov: thanks, I appreciate the heads-up.
FWIW, the purpose of my
SimulationWorker
class is, as you probably gathered, to compute some mathematical model, so I don't want this work to overload the main thread (and therefore "freeze" my GUI), hence I indeed decided to move it to a separate thread.Regarding the
Simulation
object I pass to mySimulationWorker
object, it is used to retrieve some information about my simulation (which have been set before running the worker and that don't get changed during the worker's lifespan), as well as add to it the results of the worker (i.e. simulation results). Then, my main thread (and the reason I originally decided to have that QTimer::singleSlot() calls) checks whether new results are available. So, no writing there, just fetching.Anyway, I appreciate that it could be improved when it comes thread safety, and I will make sure that it is. FWIW, I did, at some point, rely on the signal/slot mechanism for my worker, but it slowed things down quite a bit, hence I went for the approach I have just described above.
-
@kshegunov: thanks, I appreciate the heads-up.
FWIW, the purpose of my
SimulationWorker
class is, as you probably gathered, to compute some mathematical model, so I don't want this work to overload the main thread (and therefore "freeze" my GUI), hence I indeed decided to move it to a separate thread.Regarding the
Simulation
object I pass to mySimulationWorker
object, it is used to retrieve some information about my simulation (which have been set before running the worker and that don't get changed during the worker's lifespan), as well as add to it the results of the worker (i.e. simulation results). Then, my main thread (and the reason I originally decided to have that QTimer::singleSlot() calls) checks whether new results are available. So, no writing there, just fetching.Anyway, I appreciate that it could be improved when it comes thread safety, and I will make sure that it is. FWIW, I did, at some point, rely on the signal/slot mechanism for my worker, but it slowed things down quite a bit, hence I went for the approach I have just described above.
@agarny said in QTimer::singleShot()'s syntax:
Anyway, I appreciate that it could be improved when it comes thread safety, and I will make sure that it is. FWIW, I did, at some point, rely on the signal/slot mechanism for my worker, but it slowed things down quite a bit, hence I went for the approach I have just described above.
See http://doc.qt.io/qt-5/threads-synchronizing.html It sounds like the high-level approach slows things down noticeably for you, so go with the low-level ones instead.
-
@agarny said in QTimer::singleShot()'s syntax:
Anyway, I appreciate that it could be improved when it comes thread safety, and I will make sure that it is. FWIW, I did, at some point, rely on the signal/slot mechanism for my worker, but it slowed things down quite a bit, hence I went for the approach I have just described above.
See http://doc.qt.io/qt-5/threads-synchronizing.html It sounds like the high-level approach slows things down noticeably for you, so go with the low-level ones instead.
@JKSH said in QTimer::singleShot()'s syntax:
See http://doc.qt.io/qt-5/threads-synchronizing.html It sounds like the high-level approach slows things down noticeably for you, so go with the low-level ones instead.
Yes, I am already using low-level synchronization primitives in parts of my code, and this is the approach I am thinking of taking here too.
-
Ok, on further investigation, the symptom described in my original message is not the result of a race condition. I agree that it is not to say that my code is free of race conditions, although I am relatively confident that it is. Not so much because of the quality of my code, but rather because of the way it is used. Now, I know it's not great, but that's the compromise I had to make for my code to be as fast as possible, something that is important for my application.
Anyway, among other things, my application can "run" mathematical models and, until recently, it could only render one run at a time. Recently, I have modified my application so that it could render multiple runs and this is where the problem was. I wasn't properly handling multiple runs and because of the low overhead associated with the new QTimer::singleShot syntax (compared with the old syntax), my application didn't render the end of some runs. I now "properly" handle multiple runs and everything works as expected (see here for those who had a look at my code before).
So, thanks all for your feedback, it was much appreciated. (Thanks @VRonin for your
std::bind()
suggestion, which I now use.) -
Ok, on further investigation, the symptom described in my original message is not the result of a race condition. I agree that it is not to say that my code is free of race conditions, although I am relatively confident that it is. Not so much because of the quality of my code, but rather because of the way it is used. Now, I know it's not great, but that's the compromise I had to make for my code to be as fast as possible, something that is important for my application.
Anyway, among other things, my application can "run" mathematical models and, until recently, it could only render one run at a time. Recently, I have modified my application so that it could render multiple runs and this is where the problem was. I wasn't properly handling multiple runs and because of the low overhead associated with the new QTimer::singleShot syntax (compared with the old syntax), my application didn't render the end of some runs. I now "properly" handle multiple runs and everything works as expected (see here for those who had a look at my code before).
So, thanks all for your feedback, it was much appreciated. (Thanks @VRonin for your
std::bind()
suggestion, which I now use.)@agarny said in QTimer::singleShot()'s syntax:
Now, I know it's not great, but that's the compromise I had to make for my code to be as fast as possible, something that is important for my application.
Are you really going to say that fast code must be buggy?
Good luck with newer versions of your project. It may work more or less now, but when you add functionality sooner or later all uncleanliness hits back.
-
@agarny said in QTimer::singleShot()'s syntax:
Now, I know it's not great, but that's the compromise I had to make for my code to be as fast as possible, something that is important for my application.
Are you really going to say that fast code must be buggy?
Good luck with newer versions of your project. It may work more or less now, but when you add functionality sooner or later all uncleanliness hits back.
@aha_1980 said in QTimer::singleShot()'s syntax:
@agarny said in QTimer::singleShot()'s syntax:
Now, I know it's not great, but that's the compromise I had to make for my code to be as fast as possible, something that is important for my application.
Are you really going to say that fast code must be buggy?
No, this is not what I am going to say otherwise I would have already said it.
I merely said that to get the speed I was after I felt the need to make some compromises and that I am aware of their limitations, hence I have done my best to ensure that my code doesn't result in a race condition, etc. Should I ever find a solution that is "cleaner" and as fast as my current solution, then I will clearly implement it.
(Thanks for the sarcasm.)
-
@aha_1980 said in QTimer::singleShot()'s syntax:
@agarny said in QTimer::singleShot()'s syntax:
Now, I know it's not great, but that's the compromise I had to make for my code to be as fast as possible, something that is important for my application.
Are you really going to say that fast code must be buggy?
No, this is not what I am going to say otherwise I would have already said it.
I merely said that to get the speed I was after I felt the need to make some compromises and that I am aware of their limitations, hence I have done my best to ensure that my code doesn't result in a race condition, etc. Should I ever find a solution that is "cleaner" and as fast as my current solution, then I will clearly implement it.
(Thanks for the sarcasm.)
@aha_1980's point is that you're building a house of cards here. Even if you don't see the effects now it is going to bite you in the a$$ sometime along the road. Remember what I wrote before: "If it works, it's the hand of god", well that's what he and I both mean. It's your code in the end and you can conduct your business as you like, we just felt it's a rather weak argument to ignore the simmering reality because you couldn't get enough speed at the time. In the end the speed would not matter if you don't get correct results, would it?
-
@aha_1980's point is that you're building a house of cards here. Even if you don't see the effects now it is going to bite you in the a$$ sometime along the road. Remember what I wrote before: "If it works, it's the hand of god", well that's what he and I both mean. It's your code in the end and you can conduct your business as you like, we just felt it's a rather weak argument to ignore the simmering reality because you couldn't get enough speed at the time. In the end the speed would not matter if you don't get correct results, would it?
@kshegunov: I do hear what you are both saying, believe it or not (see above my comment about ever finding a "cleaner" solution).
-
@kshegunov: I do hear what you are both saying, believe it or not (see above my comment about ever finding a "cleaner" solution).
@agarny @JonB @aha_1980 @J-Hilk @JKSH @kshegunov @mrjj @VRonin
I would like to add condition to singleshot like that
bool youCanRun = true; timer.singleShot(1000, this, &MyClass::mySlot, youCanRun ); // if youCanRun == true => singleshot will work // else singleshot won't work
Note : "youCanRun" could be changed in singleshot waiting time
Is there any syntax or methot I could use?
-
@agarny @JonB @aha_1980 @J-Hilk @JKSH @kshegunov @mrjj @VRonin
I would like to add condition to singleshot like that
bool youCanRun = true; timer.singleShot(1000, this, &MyClass::mySlot, youCanRun ); // if youCanRun == true => singleshot will work // else singleshot won't work
Note : "youCanRun" could be changed in singleshot waiting time
Is there any syntax or methot I could use?
@Joe-von-Habsburg said in QTimer::singleShot()'s syntax:
@agarny @JonB @aha_1980 @J-Hilk @JKSH @kshegunov @mrjj @VRonin
I would like to add condition to singleshot like that
bool youCanRun = true; timer.singleShot(1000, this, &MyClass::mySlot, youCanRun ); // if youCanRun == true => singleshot will work // else singleshot won't work
Note : "youCanRun" could be changed in singleshot waiting time
Is there any syntax or methot I could use?
Use a lambda. Check the value of
youCanRun
and call your slot if it istrue
.bool youCanRun = true; // NOTE: This variable must not go out-of-scope before the timer is triggered QTimer::singleShot(1000, this, [&]{ if (youCanRun) this->mySlot(); else qDebug("You cannot run!"); });
-
@Joe-von-Habsburg said in QTimer::singleShot()'s syntax:
@agarny @JonB @aha_1980 @J-Hilk @JKSH @kshegunov @mrjj @VRonin
I would like to add condition to singleshot like that
bool youCanRun = true; timer.singleShot(1000, this, &MyClass::mySlot, youCanRun ); // if youCanRun == true => singleshot will work // else singleshot won't work
Note : "youCanRun" could be changed in singleshot waiting time
Is there any syntax or methot I could use?
Use a lambda. Check the value of
youCanRun
and call your slot if it istrue
.bool youCanRun = true; // NOTE: This variable must not go out-of-scope before the timer is triggered QTimer::singleShot(1000, this, [&]{ if (youCanRun) this->mySlot(); else qDebug("You cannot run!"); });
@JKSH thank you :)