"QTimer can only be used with threads started with QThread" warning



  • Hi, I am developing an application where I have an object (let's call it parent) which has QAudioOutput instance (let's call it child) as its member. X is being created inside the run method of a POSIX thread. As a result, I am getting this following warning -

    @QObject::startTimer: QTimer can only be used with threads started with QThread@

    child is only being used to write audio data into the audio device and I am not using any kinds of timers inside parent. All that parent does is check some buffer to see if there is any data available and if there is, it writes it into the device using child. Otherwise it goes to sleep for 10 miliseconds.

    I don't know if I can safely ignore this warning. I tried to use QThread instead of POSIX threads but I couldn't find a way to achieve the following with QThread -

    @while(true)
    {
    if(some_condition_is_true)
    exit thread safely;

    if(buffer_is_empty)
        goto sleep_for_10_miliseconds;    // this is necessary as it immediately 
                                           // relinquishes CPU rather than waiting 
                                           // in the event loop
    
    parent.play_audio_using_child();
    

    }@

    Can I safely ignore this warning? If I can't then is there any way I can code the above procedure using QThread?



  • No, you can't. The timer isn't started.

    Why should there be any problem with your code in a QThread? If it works with posix threads, it should work with QThread too. And if in doubt: just try and don't wait for a forum to answer - you might get a faster response to your question this way :-)



  • [quote author="Volker" date="1320409501"]Why should there be any problem with your code in a QThread?[/quote]

    I tried to do that using QThread the following way -

    @class Player : public QThread
    {
    ........

    void run()
    {
        while(true)
        {
            // my previous code
        }
    }
    

    }@

    The problem is, now I don't know how can I safely terminate this Player thread from another thread, since I cannot send any signal to it (no event loop). Even if I enter into the event loop in the run method and move my code to another method in that thread class (which will then be started using signals from another thread), it won't terminate if I later send a signal to its quit slot because it's executing the code in that while loop. If I use POSIX threads then I can call pthread_cancel from another thread using this thread's id which will cause it to terminate. I couldn't find this type of termination mechanism in Qt. Is this kind of termination available?



  • You can have signals and slots between threads. This should enable you to send a "stop work and terminate" signal to your thread class. Connect the signal to a slot in your thread (or better in your worker object - see wiki article about "Threads, Events and Objects":/wiki/Threads_Events_QObjects for details). The slot can quit the event loop or set an internal flag.



  • You can QThread::terminate() a QThread as well, but terminating a thread is (usually) not what you want to do. A better approach is to just leave the run() method.

    @
    class Player : public QThread
    {
    public:
    Player(QObject* parent = 0) : QThread(parent), _shutdown(false)
    {
    }

    public slots:
    void shutdown() { _shutdown = true; }

    protected:
    void run()
    {
    while(_shutdown == false)
    {
    ...
    }
    }

    private:
    bool _shutdown;
    }
    @
    Brain to terminal. Not tested. Probably further thread-safety required.

    If you need an id to QThread mapping just create one on your own, for example using QHash<int, QThread*>.



  • [quote author="Volker" date="1320412585"]You can have signals and slots between threads. This should enable you to send a "stop work and terminate" signal to your thread class.[/quote]

    If I implement my run method in the above way, then the only way to enable signal-slot across threads (that is, to enter into the event loop) is to call the exec() method before the while loop, and I don't think that's gonna solve my problem.

    @Lukas: Yes, I was thinking about this same strategy too. Since apparently there is no cleaner way to do this, I have to use this one.


  • Moderators

    I have not read in detail, what the problem is about in here, but since majority of the discussion seems to be about QThread, I'll suggest reading http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/



  • @sierdzio: Yes I have read this article (and also probably all of the thread-related recommended articles too). I think this is a nice way to write threaded application, but there are some drawbacks too.

    For example, when none of the slots of a thread is currently executing it still hogs the processor by just waiting in the event loop. In my audio application I have 4 threads and all of them are really critical and important. So when one is hogging the processor the others are waiting to get a time slice, resulting in poor performance (glitchy/delayed audio output). I don't want threads to hog processor time just to execute its event loop, I want it to go to sleep if it has nothing else to do. And the only way to make that happen is to call sleep method which is unfortunately a protected member of the QThread class.

    Next, Qt's QAudioOutput class behaves in a strange way (at least, to me). It has a method called start which when called return a reference to output device's buffer and then waits for users to provide data as fast as possible so that it may render them (this mode is being called"push" mode). If the client can't provide data at a fast enough rate, then it runs into underrun error, changes its state to IDLE state and stops rendering (doesn't it supposed to wait until user "push"es data?!?!?). It again starts rendering when user writes data into it, moving to its active state. These changes of states result in a really glitchy audio output. To avoid this unnecessary state transition, output may be suspended by calling suspend, which then temporarily stops rendering audio data, preserving buffer data. But it just makes matter much worse and the voice becomes unrecognizable.The only way to avoid this glitch is to put this object's thread to sleep which will result in a good quality voice (Yes I have tested it with POSIX threads, no glitches/delays there).

    If any one of these 4 threads ever hogs processor time just to wait in the event loop, the resulting output becomes really poor.

    I hope I have made myself clear this time.



  • Me again ... That's right, don't use an event loop in the QThread that you use to do the realtime audio processing. In that case, use a volatile boolean flag that you may set from the "master control thread"... That should be ok, as it is a simple flag that you only read in your audio loop.

    @void run()
    {
    while(!stopIt) // volatile bool stopIt ...
    {
    // my previous code
    }@



  • @vidar: Looks like you are always ready with some good suggestion for me :-). Thank you very much for the volatile variable suggestion, I will certainly keep that in mind.

    And thanks again :-).


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.