9

I created a multithreaded application in Qt (4.7.2). Only the main thread has an event loop.

The issue is that sometimes I get the following warning in the console:

QObject::startTimer: timers cannot be started from another thread

After this happens, the app consumes 100% of CPU (I have a single core CPU). It seems, that the main thread consumes all of the CPU's resources. The program does not freeze, and everything still works.

When I stop the program in the debugger, I do not see my code in the call stack.

The problem is that I'm not using (explicitly, anyway) timers at all.

What could it be connected with? I know, that question is very common, but I can't even understand, what piece of code to show.

Bart
  • 19,692
  • 7
  • 68
  • 77
Lol4t0
  • 12,444
  • 4
  • 29
  • 65
  • 1
    are you using QObject-based classes in your worker threads? or signal-slot system,for example. If answer is yes, redesign your app not to use qobjects, or add some sort of event loop to objects created in your thread. This also may be a result of data corruption, for example as result of using non-thread-safe methods of data interchanging between your threads... – Raiv Jul 18 '11 at 12:28
  • 2
    Many Qt classes use `QTimer` internally ... especially GUI ones can you give more details about what your code is meant to do in the worker threads ? – Thomas Vincent Jul 18 '11 at 14:43
  • 1
    Some threads, that send data in synchronous mode using 3rd party libriary (non Qt one) to com port & logs data to treewidgets. May be, it worth using signals/slots to interact with GUI? Or any else technique? Note, that finally fails main thread (when all working threads already exited, program still consumes CPU, but it's enough to suspend main thread (using OS sleep function) to stop it) – Lol4t0 Jul 18 '11 at 15:50

2 Answers2

10

Thanks, to @vrince I've fixed the problem. I used signals/slots mechanism + Qt::QueuedConnection to communicate with GUI

For example, if I need to set text of QLabel from worker thread, I can make in my worker thread signal

void textChanged(QString);

then I connect this signal to the slot of QLabel using Qt::QueuedConnection

connect(worker, SIGNAL(textChanged(QString)), label, SLOT(setText(QString), Qt::QueuedConnection);

If I want to execute setText synchronously, I can use Qt::BlockingQueuedConnection

now in my worker thread I just emit signal:

emit textChanged(newText);

Also, it is possible to use QMetaObject functions to avoid signals and slots:

metaObject->invokeMethod(label, "setText", Qt::QueuedConnection, Q_ARG(QString, text));
Lol4t0
  • 12,444
  • 4
  • 29
  • 65
  • 1
    can you write some example? I have similar problem, for example I want to change text of plainTextEdit in my GUI from my working thread: `self.ui.plainTextEdit.appendPlainText(sometext)`, please explain this to me. – Aleksandar Nov 27 '12 at 12:54
  • 1
    @Aleksandar, I've expanded my answer. I've learned a lot since that time, hehe – Lol4t0 Nov 27 '12 at 18:41
1

One of several initially baffling PyQt "warnings" (with consequences) symptomatic of a single, classic cause: trying to manipulate GUI elements using a non-"application thread", without using signals and slots as you should.

See my answer here.

mike rodent
  • 14,126
  • 11
  • 103
  • 157