Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. [SOLVED]Multithread question
Forum Updated to NodeBB v4.3 + New Features

[SOLVED]Multithread question

Scheduled Pinned Locked Moved General and Desktop
9 Posts 4 Posters 3.3k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • R Offline
    R Offline
    ranger0
    wrote on last edited by
    #1

    Hi guys, I hope you can help me fix this:

    I'd wrote a "Sql Manager" which works in an other thread in order to not freeze my app during queries.

    I use this to retrieve search results, and I'm calling QEventLoop::exec() in order to wait until query is completed. I have this piece of code:

    @
    void app::search(QString text)
    {
    timer->start(1000);
    sqlmanager->query(/query statements/ text);
    while(timer->isActive() && canFetchMore())
    {
    fetchMore();
    }
    }
    @

    and

    @
    void app:fetchMore()
    {
    sqlmanager->query(/query statements/);
    //set canFetchMore
    }
    @

    My problem is:

    Both search and fetchMore functions use the same Sql Manager. When I call search before canFetch is completed it starts and finishes this function before fetchMore is completed, proceeding this way:

    Start search;
    Finish search;
    Start canFetch;
    Start search; (new call)
    Finish search;
    Finish canFetch;

    Due to the signal/slot mechanism used to communicate with Sql Manager (in other thread), I'm getting the response from canFetch into new search call.

    Does anyone know how to solve this?

    Thanks.

    1 Reply Last reply
    0
    • A Offline
      A Offline
      Adrien Leravat
      wrote on last edited by
      #2

      A few questions:

      • which thread owns your "app" instance ?
      • how do you created your thread ?
      • how are you using your qeventloop ?
      • what's in your canFetch method ? (and is it canFetchMore ?)

      We're lacking a few details to help you.

      Adeneo Embedded - www.adeneo-embedded.com

      1 Reply Last reply
      0
      • E Offline
        E Offline
        eyyakeen
        wrote on last edited by
        #3

        The problem may be sourced from different reasons. If you can give more information about the sql-manager thread, it could be given more useful information. As far as I saw from your scripts, you should omit timer->isActive() and use QTime *t and t->elapsed() for your purpose. Also calling the thread is a right manner is important, if you cause a way to run it abnormally, you can get irregular results.

        Please look at here for problems related with timer :

        "here":http://stackoverflow.com/questions/4695044/qt-how-to-use-qtimer-to-print-a-message-to-a-qtextbrowser-every-10-seconds
        and
        "here":http://stackoverflow.com/questions/4834074/qt-how-to-delay-a-program-while-qtimer-is-active

        1 Reply Last reply
        0
        • U Offline
          U Offline
          utcenter
          wrote on last edited by
          #4

          ranger0 - do you use queued connection for signals and slots?

          1 Reply Last reply
          0
          • R Offline
            R Offline
            ranger0
            wrote on last edited by
            #5

            [quote author="Adrien Leravat" date="1359637461"]A few questions:

            • which thread owns your "app" instance ?
            • how do you created your thread ?
            • how are you using your qeventloop ?
            • what's in your canFetch method ? (and is it canFetchMore ?)

            We're lacking a few details to help you.[/quote]

            Adrien,

            My "app" instance is owned by GUI thread.
            My thread was created as follows:
            @
            dbObject * db = new dbObject;
            QThread * threaddb = new QThread(this);

            //connections

            db->moveToThread(threaddb);
            threaddb->start(QThread::IdlePriority);
            @

            QEventLoop is used in order to wait thread response as follows:
            @
            //Emit signal to thread
            QEventLoop * loop = new QEventLoop;
            loop->exec();
            //Return thread response
            @

            My canFetchMore method just returns whether is possible fetch more results, which is different from fetchMore method which actually calls Sql Mannager.

            Thanks for your help.

            1 Reply Last reply
            0
            • R Offline
              R Offline
              ranger0
              wrote on last edited by
              #6

              [quote author="utcenter" date="1359650713"]ranger0 - do you use queued connection for signals and slots?[/quote]

              utcenter,

              As Qt 4 documentation says, it's default when connecting different threads.

              It's working right.

              Thank you.

              1 Reply Last reply
              0
              • A Offline
                A Offline
                Adrien Leravat
                wrote on last edited by
                #7

                From what I saw, I'd say there is a little design problem.

                If you want to use a thread to fetchData for 1 second (that's what I understand from you code, not each second), then you could:

                • Add a newSearchStarted to app
                • Add a search slot to dbObject
                • Add a resultsFound signal to dbObject
                • Add a onResultsFound slot to app

                This way you communicate asynchronously with your dbObject, only with signals/slots, and you dbObject will let you know when it found new results.

                @
                dbObject * db = new dbObject;
                QThread * threaddb = new QThread(this);

                //connections
                db->moveToThread(threaddb);
                connect(db, SIGNAL(resultsFound(...), this, SLOT(onResultsFound(...));
                connect(this, SIGNAL(newSearchStarted(const QString&)), db, SLOT(search(const QString&));
                threaddb->start(QThread::IdlePriority);
                @

                In your dbObject class
                @
                dbObject::dbObject()
                {
                connect(timer, SIGNAL(timeout()), this, SLOT(fetchMore()));
                timer->setSingleShot(true);
                timer->setDuration(0);
                }
                void dbObject::newSearchStarted(const QString& text)
                {
                // Do what's needed to stop previous running search if any
                // And init search/save search text

                // Start the "fetchMore" loop
                fetchMore();
                }

                void dbObject::fetchMore()
                {
                sqlmanager->query(/query statements/ text);
                emit resultsFound(...); // Parse you results

                if (canFetchMore())
                {
                // Post a signal that will be processed immediately as thread returns to its event loop, but yet can be interrupted ( for exemple by a new search)
                timer->start();
                }
                }
                @

                In you app class code
                @
                void app::onSearchButtonClicked()
                {
                ...
                emit newSearchStarted(sSearchString);
                ...
                }

                void app::onResultsFound(...)
                {
                // Handle your data
                }
                @

                Finally, I don't think you need a QEventLoop. Simply a thread owning your dbObject, and signal/slots

                Adeneo Embedded - www.adeneo-embedded.com

                1 Reply Last reply
                0
                • R Offline
                  R Offline
                  ranger0
                  wrote on last edited by
                  #8

                  Hi Adrien,

                  I appreciate very much your help!

                  I'd like to discuss with you how you would stop running searches. Due to signal/slot mechanism, all signals from different threads are queued. It means that if I ask for a new search, it will be processed only when the current one is finished and therefore, there will be nothing to stop.

                  Due to details not shown here yet, I really need a QEventLoop to wait until dbObject response. So I could solve this problem using the code below:

                  @
                  void app::search(QString text)
                  {
                  if(!searchIsRunning)
                  {
                  searchIsRunning = true;
                  timer->start(1000);
                  sqlmanager->query(/query statements/ text);
                  while(timer->isActive() && canFetchMore())
                  {
                  fetchMore();
                  }
                  searchIsRunning = false;
                  emit searchFinished();
                  }
                  else
                  {
                  searchText.append(text); //QStringList
                  connect(this,SIGNAL(searchFinished()),this,SLOT(newSearch()));
                  }
                  }

                  void app:newSearch()
                  {
                  disconnect(this,SIGNAL(searchFinished()),0,0);
                  search(searchText.last());
                  searchText.clear();
                  }
                  @

                  This way I prevent two simultaneous calls to dbObject, but I think that killing the previous call and start a new one would be a better solution. What do you think?

                  Best regards and thank you for your help.

                  1 Reply Last reply
                  0
                  • A Offline
                    A Offline
                    Adrien Leravat
                    wrote on last edited by
                    #9

                    [quote author="ranger0" date="1359713906"]Due to signal/slot mechanism, all signals from different threads are queued. It means that if I ask for a new search, it will be processed only when the current one is finished and therefore, there will be nothing to stop.[/quote]

                    Well... actually no, because of the use of a QTimer, that will post an event that will be processed the same way as the newSearchStarted signal in my example.

                    • Thread1- newSearchStarted signal ->>
                    • Thread2->> search slot from Thread1 -> fetchMore (starts QTimer)
                    • Thread1- newSearchStarted signal ->>
                    • Thread2->> fetchMore from QTimer (starts QTimer)
                    • Thread2->> search slot from Thread1 -> stop previous search (for exemple by incrementing a "searchId" variable, tested at the beginning of fetchMore) and call fetchMore (starts QTimer)

                    So if you fetching mecanism allow to execute multiple consecutive queries done in fetchMore, the search will stop half way if another search is requested. Infinite loops like the one you did with while(timer->isActive()) should be avoided as it prevents the thread from processing events until done. Which is not the case using a timer with a 0ms timeout. This is a common way to achieve this, as pointed by eyyakeen.

                    Adeneo Embedded - www.adeneo-embedded.com

                    1 Reply Last reply
                    0

                    • Login

                    • Login or register to search.
                    • First post
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • Users
                    • Groups
                    • Search
                    • Get Qt Extensions
                    • Unsolved