Im using wxWidgets and I call function which takes a long time to proceed. I would like to do it in background.
How can I do that?
Thanks for help
I've worked with threads in wxWidgets in pretty much all of the ways described here, and I can say that using custom events, while initially a bit more complex, saves you some headache in the long run. (The wxMessageQueue class is quite nice, but when I used it I found it to leak; I haven't checked it in about a year though.)
A basic example:
MyFrm.cpp
#include "MyThread.h"
BEGIN_EVENT_TABLE(MyFrm,wxFrame)
EVT_COMMAND(wxID_ANY, wxEVT_MYTHREAD, MyFrm::OnMyThread)
END_EVENT_TABLE()
void MyFrm::PerformCalculation(int someParameter){
//create the thread
MyThread *thread = new Mythread(this, someParameter);
thread->Create();
thread->Run();
//Don't worry about deleting the thread, there are two types of wxThreads
//and this kind deletes itself when it's finished.
}
void MyFrm::OnMyThread(wxCommandEvent& event)
{
unsigned char* temp = (unsigned char*)event.GetClientData();
//do something with temp, which holds unsigned char* data from the thread
//GetClientData() can return any kind of data you want, but you have to cast it.
delete[] temp;
}
MyThread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <wx/thread.h>
#include <wx/event.h>
BEGIN_DECLARE_EVENT_TYPES()
DECLARE_EVENT_TYPE(wxEVT_MYTHREAD, -1)
END_DECLARE_EVENT_TYPES()
class MyThread : public wxThread
{
public:
MyThread(wxEvtHandler* pParent, int param);
private:
int m_param;
void* Entry();
protected:
wxEvtHandler* m_pParent;
};
#endif
MyThread.cpp
#include "MyThread.h"
DEFINE_EVENT_TYPE(wxEVT_MYTHREAD)
MyThread::MyThread(wxEvtHandler* pParent, int param) : wxThread(wxTHREAD_DETACHED), m_pParent(pParent)
{
//pass parameters into the thread
m_param = param;
}
void* MyThread::Entry()
{
wxCommandEvent evt(wxEVT_MYTHREAD, GetId());
//can be used to set some identifier for the data
evt.SetInt(r);
//whatever data your thread calculated, to be returned to GUI
evt.SetClientData(data);
wxPostEvent(m_pParent, evt);
return 0;
}
I feel like this is much more clear, concise example than the one the wiki offers. Obviously I left out code concerning actually launching the app (wx convention would make that MyApp.cpp) and any other non-thread-related code.
If you simply need to have something work in the background until it's finished -- fire and forget if you will, something like this:
// warning: off the top of my head ;-)
class MyThread
: public wxThread
{
public:
MyThread() : wxThread(wxTHREAD_DETACHED)
{
if(wxTHREAD_NO_ERROR == Create()) {
Run();
}
}
protected:
virtual ExitCode Entry()
{
// do something here that takes a long time
// it's a good idea to periodically check TestDestroy()
while(!TestDestroy() && MoreWorkToDo()) {
DoSaidWork();
}
return static_cast<ExitCode>(NULL);
}
};
MyThread* thd = new MyThread(); // auto runs & deletes itself when finished
A few tips from implementing the above:
Using MingW32 and Codeblocks I've had the following warning: EVENT redeclared without dllimport attribute: previous dllimport ignored. The soultion to this is that if you do not need to export your events, use DEFINE_LOCAL_EVENT_TYPE and DECLARE_LOCAL_EVENT_TYPE (instead of DEFINE_EVENT_TYPE and DECLARE_EVENT_TYPE).
If you want to pass objects via SetClientData(), make sure you create the data using the new operator in the detachable thread. The calling application will then have to delete the data once it's copied.
For example:
BEGIN_DECLARE_EVENT_TYPES()
DECLARE_LOCAL_EVENT_TYPE(wxEVT_CALC_THREAD, -1)
END_DECLARE_EVENT_TYPES()
void* MyThread::Entry()
{
wxCommandEvent evt(wxEVT_CALC_THREAD, GetId());
// do some work
vector<map<int, int> > *vm = new vector<map<int, int> >();
// perform operations with the object vm ...
evt.SetClientData((void*)vm);
wxPostEvent(m_pParent, evt);
}
and in the calling application:
DEFINE_LOCAL_EVENT_TYPE(wxEVT_CALC_THREAD)
// change this to your event table
BEGIN_EVENT_TABLE(..., ...)
EVT_COMMAND(wxID_ANY, wxEVT_CALC_THREAD, ThreadDone)
END_EVENT_TABLE()
void ThreadDone(wxCommandEvent& event)
{
vector<map<int, int> > *temp = (vector<map<int, int> > *)event.GetClientData();
// store the data in *temp
delete temp;
}
If your program is simple and you don't want to mess around with threads, you may consider calling wxWindow::Update() periodically in your long function.
Related
I want to enable a pushbutton in a callback function. I have tried to do the following but I have got:
Runtime received SIGSEGV (address: 0x28 reason: address not mapped to object)
class MyWindow: public QDialog
{
Q_OBJECT
public:
QPushButton *Btn;
void Scan();
....
};
extern void StartScan(pfcallback);
void MyWindow::Scan()
{
Btn->setEnabled(false);
StartScan(Scanfinished);
}
void static Scanfinished()
{
Btn->setEnabled(true);
}
How to access the button in the callback function Scanfinished() ?
You're attempting to manually manage memory. As you can see, it's very easy to use a dangling pointer or commit other blunders. Instead, let the compiler do it for you.
You use static incorrectly.
If I were to do it, I'd do as follows. The destructor is generated by the compiler and will correctly release all resources and reset m_instance to a null value.
class MyWindow : public QDialog
{
Q_OBJECT
static QPointer<MyWindow> m_instance;
QVBoxLayout m_layout{this};
QPushButton m_button{"Scan"};
public:
MyWindow(QWidget * parent = nullptr) : QDialog(parent) {
Q_ASSERT(! m_instance);
m_instance = this;
m_layout.addWidget(&m_button);
}
void Scan();
static void ScanFinished();
};
QPointer<MyWindow> MyWindow::m_instance;
void StartScan(void(*callback)());
void MyWindow::Scan()
{
m_button.setEnabled(false);
StartScan(ScanFinished);
}
void MyWindow::ScanFinished()
{
m_instance->m_button.setEnabled(true);
}
At this point it's rather obvious that the API of StartScan is horribly broken, and this brokenness forces the use of a singleton MyWindow. When doing any kind of callbacks, you never use a sole C function pointer. You must accept both a function pointer that takes a void* and a void* that will be used to carry the data the function needs to work. This is an idiom. If you use C-style callbacks, you cannot not use the idiom without severely crippling the usability of your API.
Thus, this is a complete example and works in both Qt 4 and Qt 5. You should have posted something like it - a self-contained test case - in your question. It compiles and it works and you can even get the complete Qt Creator project from github. It will compile and run on all platforms supported by current Qt. It's not supposed to be hard: that's why you're using Qt, after all. Getting in the habit of creating such concise test cases to demonstrate your issues will make you a better developer, and make your questions much easier to answer.
// https://github.com/KubaO/stackoverflown/tree/master/questions/simple-callback-43094825
#include <QtGui>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#include <QtConcurrent>
#endif
class MyWindow: public QDialog
{
Q_OBJECT
QVBoxLayout m_layout{this};
QPushButton m_button{"Scan"};
Q_SIGNAL void ScanFinished();
public:
MyWindow(QWidget * parent = nullptr) : QDialog(parent) {
m_layout.addWidget(&m_button);
connect(&m_button, SIGNAL(clicked(bool)), this, SLOT(Scan()));
connect(this, SIGNAL(ScanFinished()), this, SLOT(OnScanFinished()));
}
Q_SLOT void Scan();
static void ScanFinishedCallback(void* w);
Q_SLOT void OnScanFinished();
};
void StartScan(void(*callback)(void*), void* data) {
// Mockup of the scanning process: invoke the callback after a delay from
// a worker thread.
QtConcurrent::run([=]{
struct Helper : QThread { using QThread::sleep; };
Helper::sleep(2);
callback(data);
});
}
void MyWindow::Scan()
{
m_button.setEnabled(false);
StartScan(ScanFinishedCallback, static_cast<void*>(this));
}
void MyWindow::ScanFinishedCallback(void* data)
{
emit static_cast<MyWindow*>(data)->ScanFinished();
}
void MyWindow::OnScanFinished()
{
m_button.setEnabled(true);
}
int main(int argc, char ** argv) {
QApplication app(argc, argv);
MyWindow w;
w.show();
return app.exec();
}
#include "main.moc"
Of course StartScan cannot do the work in the thread it was called from: it'd block the GUI thread and make your application unresponsive. That's the prime source of bad user experience. Instead, it should spawn a concurrent job that will notify the caller when the scanning is done.
Since the callback will be called from that concurrent thread, it's not safe to use MyWindow's non-thread-safe methods. The only thread-safe methods are signals - thus we can emit a signal that Qt will the safely forward to MyWindow's thread and invoke OnScanFinished from the right thread.
I have implemented a class in Qt to receive char inputs and filter them and return meaningful char arrays to me, and also this is done in a different thread than the original thread.
Here's the header file:
class WorkerThread : public QObject
{
Q_OBJECT
QThread highspeedthread;
int bufferCounter=0;
public:
char buffer[260];
WorkerThread();
public slots:
void doWork(char parameter); // This is the function to do the filtering
signals:
void resultReady(char*); // Signal for when the result is made, It gets connected to HighspeedProcessor::handleresult
};
class HighspeedProcessor : public QObject
{
Q_OBJECT
QThread highspeedthread;
public:
HighspeedProcessor();
signals:
void process(char); // This is the function from which the cycle starts
public slots:
void handleResult(char*); // This gets the results back
};
And here's the definitions:
void WorkerThread::doWork(char parameter)
{
buffer[bufferCounter] = parameter;
// Filters the input and fills the buffer
// Code omitted for easement
// ...
qDebug()<<"Before: "<<buffer;
emit resultReady(buffer); // Pass the buffer to HighspeedProcessor::handleResult
}
HighspeedProcessor::HighspeedProcessor() {
WorkerThread *worker = new WorkerThread;
worker->moveToThread(&highspeedthread);
connect(this, SIGNAL(process(char)), worker, SLOT(doWork(char)));
connect(worker,SIGNAL(resultReady(char*)), this,SLOT(handleResult(char*)));
highspeedthread.start();
}
void HighspeedProcessor::handleResult(char *parameter)
{
qDebug()<<"After: "<<parameter;
}
The WorkerThread is doing its work just fine and filters results flawlessly, but problem is that when the result is passed to the HighspeedProcessor class, the char array gets mixed up. The result is as shown below:
Before: $CMDgFlushing FIFO
After: $CMDgFlushing FIFO�:�"��ά!���j�D��#�/�]%�i�����Rր�������y�r��<�F��!]�uh����q�=S�ߠ�"�M�d
Before: $CMDgFlushing FIFO
After: $CMDgFlushing FIFO
Before: $CMDgFlushing FIFO
After: $CMDgFlushing ��o���kj���q�9 ����^ou����
And by the way this is not happening so frequently, meaning only once out of almost 100 times it gets mixed up and other times it's ok. Also the rate of input data is almost 1Mb/s. Am I doing something wrong?
EDIT: This was already happening before I used qDebug in my code. So, it's not the result of using qDebug.
Your mistakes:
Your are using the buffer in two different threads, but are passing
only a pointer to it, it is pointless.
Don't protect a reading/writing to the buffer
You don't need even to use any thread-safe exchange buffer, you simply can pass a QByteArray as a parameter between threads through signals-slots.
For example:
QByteArray buffer;
//...
signals:
void resultReady(QByteArray);
//...
void WorkerThread::doWork(char parameter)
{
buffer[bufferCounter] = parameter;
//...
emit resultReady(buffer);
}
void HighspeedProcessor::handleResult(QByteArray parameter)
{
qDebug() << "After: "<< parameter;
}
Changing my char* variables to QByteArray solved my problem. Somehow there was some conflict happening between the two threads that used the same pointer for buffer.
I update a count down timer using timerEvent(QTimerEvent *e) once I am done I call the killTimer(timerID) but the timerEvent() is still being called.
So what's the proper way to kill it?
The Code:
void MainWindow::timerEvent(QTimerEvent *e)
{
Q_UNUSED(e);
static uint16_t u16RemTime = MAX_WARMUP_TIME_IN_SECS;
if((true == isWarmUpStarted) && (u16RemTime > 0))
{
u16RemTime--;
objptrSplashScreen->SetTime(u16RemTime);
}
else
{
//Still running
qWarning("\n\n\n\n\n WARM UP TIMER RUNNING \n\n\n\n\n");
killTimer(warmUpTimerID);
}
}
If it helps. I have two such timers running in two different classes in the same GUI thread. How would I go about killing it?
timerEvent receives all timers' events. In order to differ them QTimerEvent class have int timerId() const method. So your event should look like this:
void MainWindow::timerEvent(QTimerEvent *e)
{
if (e->timerId() != warmUpTimerID)
return;
static uint16_t u16RemTime = MAX_WARMUP_TIME_IN_SECS;
if((true == isWarmUpStarted) && (u16RemTime > 0))
{
u16RemTime--;
objptrSplashScreen->SetTime(u16RemTime);
}
else
{
//Still running
qWarning("\n\n\n\n\n WARM UP TIMER RUNNING \n\n\n\n\n");
killTimer(warmUpTimerID);
}
}
If you use a QTimer or QBasicTimer, you can call the stop() on one of those.
You need to make sure that a particular timerEvent invocation is related to your timer.
QBasicTimer is a nice convenience wrapper around a timer id, you could use it instead of the raw id.
Static variables in members of classes that can be potentially reused are a source of nasty bugs.
isWarmupStarted is redundant, its value is identical to m_warmupRemaining > 0.
You're not saving anything by explicitly using a 16 bit unsigned integer for the remaining time counter. Just use an int.
The style that explicitly mentions types in variable names is, well, if your employer isn't forcing you to use it, don't use it. It's the compiler's job to keep track of such things, not yours, and it's not C and winapi where things sometimes got hairy if you didn't do that.
Thus:
class MainWindow : public QMainWindow {
Q_OBJECT
QSplashScreen * m_splashScreen;
QBasicTimer m_warmupTimer;
int m_warmupRemaining;
void timerEvent(QTimerEvent * ev) {
if (ev->timerId() != m_warmupTimer.timerId()) return;
// No need to call the empty QMainWindow::timerEvent(ev).
// All timerEvent implementations in public Qt classes are empty,
// to make your life easier.
if (m_warmupRemaining > 0) {
m_warmupRemaining --;
m_splashScreen->SetTime(m_warmupRemaining);
} else {
m_warmupTimer.stop();
}
}
};
In my Qt5 program I have an interface with some signals.
An implementation of this interface is instanciated at start up and the signals are connected to from different parts of the program (many places).
Now I want to delete that instance and create a new instance, possibly from another implementation, and somehow maintain the signal connections so that all the places that receive the signals does not need to care that the implementation changed.
Is there any way to do this elegantly or do I have to change the architecture of program to keep control over all signal connections in one location (a lot of work)?
Example:
//PS: To be regarded as pseudocode at best, as lots of Qt boilerplate
// and error handling code has been left out, and lots of bugs are left in :-)
struct MyInterface{
virtual void doStuff()=0;
signals:
void someSignal();
}
struct MyImpX:public MyInterface{
void doStuff(){
qDebug()<<"MyImpX";
if((random()%100)<5){
emit someSignal();
}
}
}
struct MyImpY:public MyInterface{
void doStuff(){
qDebug()<<"MyImpY";
if((random()%100)<10){
emit someSignal();
}
}
}
struct MyWorker{
QTimer t;
MyInterface *inst=0;
MyWorker(MyInterface *inst):
inst(inst)
{
connect(&t,SIGNAL(timeout()),this,SLOT(doStuff()));
t.start(100);
}
void setNewInstance(MyInterface *inst){
this->inst=inst;
}
void doStuff(){
if(0!=inst){
inst->doStuff();
}
}
}
struct MyConsumer{
public slots:
void handleIt(){
qDebug()<<"Handling signal";
}
}
void main(){
QApplication app;
MyInterface *inst=new MyImpX();
MyWorker con(inst);
MyConsumer i,j,k,l;
//In this example all the connects are in one place, but
//in reality they are called from several locations that
//Are hard to control.
connect(inst,SIGNAL(someSignal()),&i,SLOT(handleIt()));
connect(inst,SIGNAL(someSignal()),&j,SLOT(handleIt()));
connect(inst,SIGNAL(someSignal()),&k,SLOT(handleIt()));
connect(inst,SIGNAL(someSignal()),&l,SLOT(handleIt()));
//[ ... At this point some time passes where the signal is working ]
//Now the instance changes, so the old connections are lost.
con.setNewInstance(new MyImpY());
delete inst;
inst=0;
//[ ... At this point some time passes where the signal is NOT working ]
app.exec();
}
You could try to implement something based on this question, but I think that'll be hacky at best.
So, instead, you could have a proxy object, which does not get changed, and which can change its connections when the actual object changes. For this, you should probably use signal-signal connections, though you could also write slots which emit signals. Question has pseudocode, so here's some pseudocode as well, to demonstrate the principle.
class MyInterfaceSignalProxy : public MyInterface {
//...
public:
void reconnect(MyInterface *newObj, MyInterface *oldObj=0) {
if(oldObj) disconnect(oldObj, 0, this, 0); // disconnect old connections
connect(newObj, SIGNAL(someSignal()), this, SIGNAL(someSignal()));
}
signals:
void someSignal();
}
Of course you could remove the oldObj parameter, and for example store the currently connected object as private variable, or just not care about disconnection earlier connectios (for example if oldObj will be deleted or otherwise disconnected elsewhere).
And then your main would start something like:
void main(){
QApplication app;
MyInterfaceSignalProxy proxy;
MyConsumer i,j,k,l;
connect(&proxy,SIGNAL(someSignal()),&i,SLOT(handleIt()));
connect(&proxy,SIGNAL(someSignal()),&j,SLOT(handleIt()));
connect(&proxy,SIGNAL(someSignal()),&k,SLOT(handleIt()));
connect(&proxy,SIGNAL(someSignal()),&l,SLOT(handleIt()));
MyInterface *inst=new MyImpX();
proxy.reconnect(inst);
//....
MyInterface *inst2=new MyImpY();
proxy.reconnect(inst2, inst);
delete inst; // whatever
My Qt application has a Qt gui (basically some buttons and an opengl context which draws data). I've also added scriptability exploiting PythonQt classes. The commands are evaluated from inside a PythonQtScriptingConsole.
I've explicitly created wrapper classes and factory methods to send C++ calls via the current python context through the console, but when running long tasks from inside the console, the gui freezes because (I think) the event loop is not processed. So a first solution would be to process the event loop with a timer, but this is both slow and kinda stupid I think, so I don't like it. A
Has someone some hint? Is the Python Global Interpreter Lock a problem here?
Yes, the GUI is freezing because the long call into Python is being executed via the UI thread. To get around this, I was able to subclass QThread and issue commands into the Python module via a Command pattern.
Before you start making calls into multiple Python modules using the following classes, be sure to initialize thread support in Python by calling PyEval_InitThreads() as you'll see in my main() function.
Good luck!
int main( int argc, char **argv ) {
QApplication qapp(argc, argv);
PyEval_InitThreads(); // IMPORTANT
PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);
PythonQtObjectPtr module = PythonQt::self()->createUniqueModule();
ThreadedPythonContext context(module);
context.start();
# issue some commands into the module
context.issue("import sys");
context.issue("sys.path.append('C:\\Python27\\Lib\\site-packages')");
context.issue("import time");
context.issue("last = time.localtime().tm_sec");
// Release the global interpreter lock (if it has been created and thread support
// is enabled) and reset the thread state to NULL, returning the previous thread
// state (which is not NULL). If the lock has been created, the current thread must
// have acquired it. (This function is available even when thread support is
// disabled at compile time.)
// give up control of the GIL
PyThreadState *state = PyEval_SaveThread();
return qapp.exec()
}
ThreadedPythonContext.h
#ifndef THREADEDPYTHONCONTEXT_H
#define THREADEDPYTHONCONTEXT_H
#include "PythonQt.h"
#include <QtCore/QMutexLocker>
#include <QtCore/QQueue>
#include <QtCore/QThread>
#include <QtCore/QWaitCondition>
class ThreadedPythonContext : public QThread
{
Q_OBJECT
public:
ThreadedPythonContext(const PythonQtObjectPtr &context) :
QThread(),
_context(context),
_running(true)
{
}
~ThreadedPythonContext() {
_running = false;
wait();
}
void issue(const QString &code) {
_lock.lock();
_commands.enqueue(code);
_lock.unlock();
_CommandQueued.wakeOne();
}
bool isCommandQueueEmpty() {
QMutexLocker lock(&_lock);
return _commands.isEmpty();
}
protected:
QString dequeue() {
QMutexLocker lock(&_lock);
QString cmd( _commands.dequeue() );
return cmd.isEmpty() ? "\n" : cmd;
}
void run() {
QMutex signal;
PyGILState_STATE state;
while(_running) {
// wait to be signaled ...
signal.lock();
_CommandQueued.wait(&signal,1);
signal.unlock();
if ( isCommandQueueEmpty() ) {
continue;
}
while ( !isCommandQueueEmpty() ) {
PythonQtObjectPtr p;
PyObject* dict = NULL;
state = PyGILState_Ensure();
if (PyModule_Check(_context)) {
dict = PyModule_GetDict(_context);
} else if (PyDict_Check(_context)) {
dict = _context;
}
if (dict) {
// this command blocks until the code has completed execution
emit python_busy(true);
p.setNewRef(PyRun_String(dequeue().toLatin1().data(), Py_single_input, dict, dict));
emit python_busy(false);
}
// error in the kernel
if (!p) {
PythonQt::self()->handleError();
}
PyGILState_Release(state);
}
}
}
PythonQtObjectPtr _context;
QMutex _lock;
QQueue<QString> _commands;
QWaitCondition _CommandQueued;
bool _running;
signals:
void python_busy(bool);
};
#endif //THREADEDPYTHONCONTEXT_H