Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Multithreading



  • First I wanted to use QThread.
    Then I did QtConcurrent::run(MyFunction); and it works quite good. So do I really need multithreading?


  • Moderators

    @jenya7 you know,
    those are 3 separate statements, that stay in no correlation to each other.

    Do you mind, connecting the dots for us?


  • Lifetime Qt Champion

    @jenya7 said in Multithreading:

    So do I really need multithreading?

    I have no idea what your use case is - be more specific to get a meaningful unswer.
    QtConcurrent::run(MyFunction) runs your function in a different thread also (it is multithreading as well). But using it you have less control and you do not have event loop in the spawned thread. So, it depends on what you want to do.



  • @jsulm said in Multithreading:

    @jenya7 said in Multithreading:

    So do I really need multithreading?

    I have no idea what your use case is - be more specific to get a meaningful unswer.
    QtConcurrent::run(MyFunction) runs your function in a different thread also (it is multithreading as well). But using it you have less control and you do not have event loop in the spawned thread. So, it depends on what you want to do.

    I have a function to read from a console in Qt Console Application

    void ConsoleTask (void)
    {
            ch_ptr = fgets(cons_str, 256, stdin);
            if (ch_ptr != nullptr)
            {
               COMPARSER_ParseCommand(trimmed_str);
            }
    }
    

    fgets - is a blocking operation. so I wanted to create a thread. Then I saw this solution
    QtConcurrent::run(ConsoleTask )
    and it works good. so why create thread?


  • Lifetime Qt Champion

    @jenya7 said in Multithreading:

    so why create thread?

    If QtConcurrent::run(ConsoleTask ) works you do not have to create a thread explicitly.
    But keep in mind that QtConcurrent::run(ConsoleTask ) creates a thread for you and executes the function there.
    And COMPARSER_ParseCommand will also be excuted in the thread QtConcurrent::run(ConsoleTask ) started.



  • @jsulm said in Multithreading:

    @jenya7 said in Multithreading:

    so why create thread?

    If QtConcurrent::run(ConsoleTask ) works you do not have to create a thread explicitly.
    But keep in mind that QtConcurrent::run(ConsoleTask ) creates a thread for you and executes the function there.

    Ah..I see. At list it removes all the burden from me

     QThread main_thread; 
     worker *m_worker = new worker();
     m_worker->moveToThread(&main_thread);
    

    and so on.

    mmm....so COMPARSER_ParseCommand can not be called from the main task?


  • Lifetime Qt Champion

    @jenya7 Yes, QtConcurrent::run() is easy to use and is good for simple use cases.


  • Moderators

    @jenya7 to add to @jsulm
    QtConCurrent is it's own module, and offers quite a lot of possibilities.

    But, since it's a module you'll have to add it to your project file, that comes with all kind of overhead.

    Therefore I suggest for you to look at the (somewhat) new static QThread function of create
    QThread *QThread::create

    in your particular case, it my be even easier than QtConcurrent



  • @J-Hilk said in Multithreading:

    @jenya7 to add to @jsulm
    QtConCurrent is it's own module, and offers quite a lot of possibilities.

    But, since it's a module you'll have to add it to your project file, that comes with all kind of overhead.

    Therefore I suggest for you to look at the (somewhat) new static QThread function of create
    QThread *QThread::create

    in your particular case, it my be even easier than QtConcurrent

    So what the cons of the module? Application size is bigger? Execution time is slower?


  • Moderators

    @jenya7 said in Multithreading:

    So what the cons of the module? Application size is bigger? Execution time is slower?

    Well, with using QtConcurrent, you expand the complexity of your application, and I assume (slightly) longer compile and linker timings.

    Application side and runtime speed sole depend on the implementation of the 2 classes. That I can't say.



  • With QtConcurrent::run(ConsoleTask ); console application runs some time (5-10 minute) and then shuts down.


  • Moderators

    @jenya7 sounds like a race condition, can you show as the content of ConsoleTask ?



  • @J-Hilk

    void ConsoleTask (void)
    {
            ch_ptr = fgets(cons_str, 256, stdin);
            if (ch_ptr != nullptr)
            {
               trimmed_str =  Trim(cons_str, TRIM_BOTH);
               COMPARSER_ParseCommand(trimmed_str);
            }
    }
    
    int main(int argc, char *argv[])
    {
       QCoreApplication a(argc, argv);
    
       motor_params_file = QCoreApplication::applicationDirPath() + "/motor_params.xml";
       sys_params_file = QCoreApplication::applicationDirPath() + "/sys_params.xml";
       script_file = QCoreApplication::applicationDirPath() + "/script.txt";
    
       GPIO_Init("/dev/gpiochip0");
       SPI_Init("/dev/spidev0.0");
       UART_Init("/dev/serial0");
       UDP_Init();
    
      SCRIPT_Load(script_file.toStdString().c_str());
    
      SYS_ParamInit(motor_params_file);
      SYS_ParamInit(sys_params_file);
    
        while (1)
        {
           udp_rx_size = UDP_Read(udp_buff_rx, 1024);
           if (udp_rx_size > 0)
           {
               printf("message size = %d \n", udp_rx_size);
               UDP_HandleRecvPacket(udp_buff_rx);
           }
    
             if(UART_Read())
             {
                   COMPARSER_ParseCommand(uart_buff_rx);
             }
    
              QtConcurrent::run(ConsoleTask);
        }
    
    }
    


  • Aaaa...I think it should be like this

    void ConsoleTask (void)
    {
        while (1)  //should be a loop!
        {
            ch_ptr = fgets(cons_str, 256, stdin);
            if (ch_ptr != nullptr)
            {
               trimmed_str =  Trim(cons_str, TRIM_BOTH);
               COMPARSER_ParseCommand(trimmed_str);
            }
        }
    }
    
    int main(int argc, char *argv[])
    {
             QtConcurrent::run(ConsoleTask);  //start here
            
             while(1)
           {
           }
    }
    
    

  • Moderators

    ok @jenya7

    that code had to set in for a moment 🙈

    A couple of things are wrong here.

    1. One you already noticed. With an infinite while loopat that place, each cycle a new QtConcurrent::run is created and executed, and you'll eventually run out of memory. Likely the cause for your crash.

    2. Why do you have a QCoreApplication instance, but no event loop? That kind of defeats the purpose and leads to this awkward situation where you have to write your own while loop

    3. ConsoleTask is clearly using member Variables (without a mutex) if they are used somewhere else than that will eventually cause problems

    4. With this approach you'll constantly block one of your cpu cores. Is this really what you want to do ? Don't tell me you want to fix that by using some kind of thread sleep function!



  • @J-Hilk said in Multithreading:

    ok @jenya7

    that code had to set in for a moment 🙈

    A couple of things are wrong here.

    1. One you already noticed. With an infinite while loopat that place, each cycle a new QtConcurrent::run is created and executed, and you'll eventually run out of memory. Likely the cause for your crash.

    2. Why do you have a QCoreApplication instance, but no event loop? That kind of defeats the purpose and leads to this awkward situation where you have to write your own while loop

    3. ConsoleTask is clearly using member Variables (without a mutex) if they are used somewhere else than that will eventually cause problems

    4. With this approach you'll constantly block one of your cpu cores. Is this really what you want to do ? Don't tell me you want to fix that by using some kind of thread sleep function!

    The target is an embedded device (RRi 4). So I run in a constant loop some tasks. besides reading from UDP and UART I analize some script and send commands to slaves.
    So what is the better option? To open a thread for each task? I don't quite understand where I end up after return a.exec(); in console application, so I did a loop.


  • Moderators

    @jenya7

    That doesn't really sound like extreme time critical operations (analize some script and send commands to slaves) or are event driven, so that you can react to events(e.g new data arrived) directly without waiting in a while loop for it. QUdpSocket and QSerialPort offer these event driven API's. There's no need for a dedicated thread for them.

    The example you posted would probably work exactly the same with a QTimer, and be more cpu friendly.

    int main(int argc, char *argv[])
    {
       QCoreApplication a(argc, argv);
    
       motor_params_file = QCoreApplication::applicationDirPath() + "/motor_params.xml";
       sys_params_file = QCoreApplication::applicationDirPath() + "/sys_params.xml";
       script_file = QCoreApplication::applicationDirPath() + "/script.txt";
    
       GPIO_Init("/dev/gpiochip0");
       SPI_Init("/dev/spidev0.0");
       UART_Init("/dev/serial0");
       UDP_Init();
    
      SCRIPT_Load(script_file.toStdString().c_str());
    
      SYS_ParamInit(motor_params_file);
      SYS_ParamInit(sys_params_file);
    
      //... etc
      QTimer t;
      QObject::connect(&t, &QTimer::timeout, &t, &ConsoleTask);
      t.start(20); //20 ms -> 50 times per second
      
        return a.exec(); //Important the EventLoop MUST run
    }
    


  • @J-Hilk said in Multithreading:

    @jenya7

    That doesn't really sound like extreme time critical operations (analize some script and send commands to slaves) or are event driven, so that you can react to events(e.g new data arrived) directly without waiting in a while loop for it. QUdpSocket and QSerialPort offer these event driven API's. There's no need for a dedicated thread for them.

    The example you posted would probably work exactly the same with a QTimer, and be more cpu friendly.

    Sorry for my slow understanding. Where do I place QUdpSocket , QSerialPort and other tasks - before return a.exec();? They will run constantly? Some task I can connect to a timer. But I have a time critical task - gather info from slaves, analyze it and send command based on the info - it should be really fast.



  • Can I find a non-trivial Console Application example to learn how to do it right?


  • Moderators

    @jenya7 said in Multithreading:

    Sorry for my slow understanding. Where do I place QUdpSocket , QSerialPort and other tasks - before return a.exec();? They will run constantly? Some task I can connect to a timer. But I have a time critical task - gather info from slaves, analyze it and send command based on the info - it should be really fast.

    that is correct, a.exec()will spin the QEventLoop and therefore your program will not exit (return from the function call) until you QApplication::quit is emitted.

    Can I find non-trivial Console Application example to learn how to do it right?

    yes of course, the examples Qt offers should actually be enough. They are compile ready and part of your Qt Installation, if you used the online installer.

    For example:
    UDP

    SerialPort



  • Thank you.


Log in to reply