Slot called multiple times to a blocking function in the same thread
-
Hello,
I was wondering what would happen if a widget in my gui was calling the same slot multiple times, so everything is happening in the same thread.
The slot is a blocking function which takes lot of time to end.
I saw that it was able to handle the signals emitting to the same slot (for example clicking a button) if there was a QApplication::processEvents(); somewhere in the slot
Would'nt it cause memory problems if the function is called again but the first call isn't finished yet ?
Thanks for help !
-
@moffa13 Hi, friend welcome.
About what you said, the same slot multiple times, maybe you wrote some code to emit the signal(value changed signal, state changed signal ...).
some time, we called the qt inner function, these function maybe changed some value and emit some signal. likeQListWidget::currentRowChanged(int currentRow) signal
- user can clicked item to emit this signal;
- i also can
setCurrentRow(row)
in my program to emit this signal.
i called this slot signal loop; like below code snippet;
connect(listWidget,&QListWidget::currentRowChanged,this,&Class::RowChanged); void Class::RowChanged(int row) { /** it is best to disconnect begin of slot fuction */ disconnect(listWidget,&QListWidget::currentRowChanged,this,&Class::RowChanged); /** maybe at here i use setCurrent() function to changed the current row ,and will emit row changed signal again */ connect(listWidget,&QListWidget::currentRowChanged,this,&Class::RowChanged); }
If I guessed wrong. Can you show some code snippet for here? it will help us to understand your problem well.
-
@moffa13 said in Slot called multiple times to a blocking function in the same thread:
Would'nt it cause memory problems if the function is called again but the first call isn't finished yet ?
Memory problems? Usually not. But you could have other issues if the slot you're calling isn't re-entrant. For example if you have a static variable inside the slot.
But in general you should avoid blocking slots and QApplication::processEvents() is nothing more than an ugly work around and a sign of bad design. Move long lasting operations to other threads. -
@joeQ The slot being called multiple time is not accidental ; it just happens for example if I push a button 2 times.
The code is here : Github
addWhateverToList is the slot being called and FilesEncrypt::getFilesFromDirRecursive is the function that takes time.
@jsulm I used QApplication::processEvents() just to test what happens if my function becames "non-blocking".
-
The correct way to proceed, as mentioned by @jsulm is to move the heavy lifting to a separate thread but,
This is a hack!
You can put a queue slot in between:
private: Q_SLOT void lenghtyOp(){ lenghtyOpQueued =false; // do the slow stuff } bool lenghtyOpQueued = false; public: Q_SLOT void queueLenghty(){ if(lenghtyOpQueued) return; lenghtyOpQueued =true; QTimer::singleShot(100,this,SLOT(lenghtyOp())); }
now connect your button to
queueLenghty
rather than tolenghtyOp
also, you probably want to add an argument to
processEvents
:QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
-
@VRonin said in Slot called multiple times to a blocking function in the same thread:
You can put a queue slot in between:
private: Q_SLOT void lenghtyOp(){ lenghtyOpQueued =false; // do the slow stuff } bool lenghtyOpQueued = false; public: Q_SLOT void queueLenghty(){ if(lenghtyOpQueued) return; lenghtyOpQueued =true; QTimer::singleShot(100,this,SLOT(lenghtyOp())); }
I prefered to use QtConcurrent::run it's much cleaner but thanks for the trick !
Thank you all for your answers :)
-
@moffa13 said in Slot called multiple times to a blocking function in the same thread:
QtConcurrent::run it's much cleaner
I don't want to be that guy, but I'd bet my left eye you are doing multi-threading wrong here. Are you sure you don't have a race-condition on
ui->tableWidget
if you use that? -
@VRonin said in Slot called multiple times to a blocking function in the same thread:
@moffa13 said in Slot called multiple times to a blocking function in the same thread:
QtConcurrent::run it's much cleaner
I don't want to be that guy, but I'd bet my left eye you are doing multi-threading wrong here. Are you sure you don't have a race-condition on
ui->tableWidget
if you use that?I don't understand why would I have this ?
Here's my final code : linkMy lambda function is not doing anything to ui->tableWidget
-
@moffa13 said in Slot called multiple times to a blocking function in the same thread:
my thread is changing is a QTableWidgetItem which cannot be changed by something else
if the QTableWidgetItem is visible in a view then the view will directly call the item for read every repaint, hence race condition
-
@VRonin said in Slot called multiple times to a blocking function in the same thread:
@moffa13 said in Slot called multiple times to a blocking function in the same thread:
my thread is changing is a QTableWidgetItem which cannot be changed by something else
if the QTableWidgetItem is visible in a view then the view will directly call the item for read every repaint, hence race condition
Actually I said something wrong. The part who is modifying the QTableWidgetItem is the QFutureWatcher<>::finished slot, which is accessed by the main thread, I think.
One question : Is it bad to lock and unlock a mutex multiple times ?For example :
_mutex.lock(); //Some var to be protected _mutex.unlock(); //Thread-safe heavy function _mutex.lock(); //Some var to be protected _mutex.unlock();
Thanks !