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. Non blocking console reading.
Forum Updated to NodeBB v4.3 + New Features

Non blocking console reading.

Scheduled Pinned Locked Moved Solved General and Desktop
20 Posts 4 Posters 2.6k Views
  • 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.
  • J Offline
    J Offline
    jenya7
    wrote on last edited by jenya7
    #1

    I have a console application

    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        SYS_ParamInit(sys_params_file);
    
        while (1)
        {
             //is blocking!!!
             ch_ptr = fgets(cons_str, 256, stdin);
    
             //also blocking!!!
            chr = static_cast<char>(fgetchar());
            
                DoSomeStuff();
         
                SCRIPT_Run();
        }
        return 0;
    }
    

    Among the other tasks I have to read a user input from a console. But all methods (fgets, fgetchar) are blocking - it stops and waits for input.
    How can I read the console input in non blocking way?

    JonBJ KroMignonK 2 Replies Last reply
    0
    • J jenya7

      I have a console application

      int main(int argc, char *argv[])
      {
          QCoreApplication a(argc, argv);
      
          SYS_ParamInit(sys_params_file);
      
          while (1)
          {
               //is blocking!!!
               ch_ptr = fgets(cons_str, 256, stdin);
      
               //also blocking!!!
              chr = static_cast<char>(fgetchar());
              
                  DoSomeStuff();
           
                  SCRIPT_Run();
          }
          return 0;
      }
      

      Among the other tasks I have to read a user input from a console. But all methods (fgets, fgetchar) are blocking - it stops and waits for input.
      How can I read the console input in non blocking way?

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by JonB
      #2

      @jenya7
      This is going to be hard (and may depend on what platform you are on). Approaches:
      https://gist.github.com/gjorquera/2576569
      https://stackoverflow.com/questions/7543313/how-to-handle-keypress-events-in-a-qt-console-application?rq=1

      Before going any further: why are you writing a QCoreApplication/console input program in the first place? And what sort of thing is it going to be doing while awaiting a non-blocking console input?

      J 1 Reply Last reply
      0
      • JonBJ JonB

        @jenya7
        This is going to be hard (and may depend on what platform you are on). Approaches:
        https://gist.github.com/gjorquera/2576569
        https://stackoverflow.com/questions/7543313/how-to-handle-keypress-events-in-a-qt-console-application?rq=1

        Before going any further: why are you writing a QCoreApplication/console input program in the first place? And what sort of thing is it going to be doing while awaiting a non-blocking console input?

        J Offline
        J Offline
        jenya7
        wrote on last edited by
        #3

        @JonB said in Non blocking console reading.:

        @jenya7
        This is going to be hard (and may depend on what platform you are on). Approaches:
        https://gist.github.com/gjorquera/2576569
        https://stackoverflow.com/questions/7543313/how-to-handle-keypress-events-in-a-qt-console-application?rq=1

        Before going any further: why are you writing a QCoreApplication/console input program in the first place? And what sort of thing is it going to be doing while awaiting a non-blocking console input?

        Actually a console input program works much faster. In some cases I don't need GUI, only user input enough. In a while(1) loop I do some tasks, like parsing script and getting data from remote sensors. Further I have to get to lower level - to operate some hardware like GPIO, UART, CAN, SPI.

        JonBJ 1 Reply Last reply
        0
        • J jenya7

          @JonB said in Non blocking console reading.:

          @jenya7
          This is going to be hard (and may depend on what platform you are on). Approaches:
          https://gist.github.com/gjorquera/2576569
          https://stackoverflow.com/questions/7543313/how-to-handle-keypress-events-in-a-qt-console-application?rq=1

          Before going any further: why are you writing a QCoreApplication/console input program in the first place? And what sort of thing is it going to be doing while awaiting a non-blocking console input?

          Actually a console input program works much faster. In some cases I don't need GUI, only user input enough. In a while(1) loop I do some tasks, like parsing script and getting data from remote sensors. Further I have to get to lower level - to operate some hardware like GPIO, UART, CAN, SPI.

          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by
          #4

          @jenya7 said in Non blocking console reading.:

          Actually a console input program works much faster.

          A dubious statement. And if you need, or may need, a GUI for other purposes you would be better starting with a GUI.

          The way you phrase your objective, and write your code so far, makes it sound like you are not really wanting to use Qt at all. If you are going to do everything yourself, and in a C way, it is not apparent you are gaining any advantage from trying to use Qt at all.

          In any case, if you persist your way I have given you the links to see what is involved in getting non-blocking console input (as you can see, not cross-platform). So there you are.

          1 Reply Last reply
          0
          • J jenya7

            I have a console application

            int main(int argc, char *argv[])
            {
                QCoreApplication a(argc, argv);
            
                SYS_ParamInit(sys_params_file);
            
                while (1)
                {
                     //is blocking!!!
                     ch_ptr = fgets(cons_str, 256, stdin);
            
                     //also blocking!!!
                    chr = static_cast<char>(fgetchar());
                    
                        DoSomeStuff();
                 
                        SCRIPT_Run();
                }
                return 0;
            }
            

            Among the other tasks I have to read a user input from a console. But all methods (fgets, fgetchar) are blocking - it stops and waits for input.
            How can I read the console input in non blocking way?

            KroMignonK Offline
            KroMignonK Offline
            KroMignon
            wrote on last edited by KroMignon
            #5

            @jenya7 said in Non blocking console reading.:

            Among the other tasks I have to read a user input from a console. But all methods (fgets, fgetchar) are blocking - it stops and waits for input.
            How can I read the console input in non blocking way?

            As I have already say to you: Qt is an asynchronous framework, and Qt needs a working event queue to be able to handle signals/slots.
            This means:

            • no forever loop
            • no active wait.

            Or, do not use Qt but another framework.
            This code will not enable Qt to work properly.
            You have to think asynchronous, which means work with events.

            I would suggest you to use something like this project QConsoleListener to handle console in/out on asynchronous way.

            It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

            J 1 Reply Last reply
            1
            • KroMignonK KroMignon

              @jenya7 said in Non blocking console reading.:

              Among the other tasks I have to read a user input from a console. But all methods (fgets, fgetchar) are blocking - it stops and waits for input.
              How can I read the console input in non blocking way?

              As I have already say to you: Qt is an asynchronous framework, and Qt needs a working event queue to be able to handle signals/slots.
              This means:

              • no forever loop
              • no active wait.

              Or, do not use Qt but another framework.
              This code will not enable Qt to work properly.
              You have to think asynchronous, which means work with events.

              I would suggest you to use something like this project QConsoleListener to handle console in/out on asynchronous way.

              J Offline
              J Offline
              jenya7
              wrote on last edited by
              #6

              @KroMignon
              I see. No looping. But

              int main(int argc, char *argv[])
              {
              	QCoreApplication a(argc, argv);
              
              	SomeSetup();
              
              	return a.exec();
              }
              

              Where do I execute periodic tasks - not event driven?

              KroMignonK 1 Reply Last reply
              0
              • J jenya7

                @KroMignon
                I see. No looping. But

                int main(int argc, char *argv[])
                {
                	QCoreApplication a(argc, argv);
                
                	SomeSetup();
                
                	return a.exec();
                }
                

                Where do I execute periodic tasks - not event driven?

                KroMignonK Offline
                KroMignonK Offline
                KroMignon
                wrote on last edited by
                #7

                @jenya7 said in Non blocking console reading.:

                Where do I execute periodic tasks - not event driven?

                What's wrong with QTimer?

                It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

                J 1 Reply Last reply
                1
                • KroMignonK KroMignon

                  @jenya7 said in Non blocking console reading.:

                  Where do I execute periodic tasks - not event driven?

                  What's wrong with QTimer?

                  J Offline
                  J Offline
                  jenya7
                  wrote on last edited by
                  #8

                  @KroMignon
                  I see. So time sensitive tasks I can run with QTimer and set zero delay? Actually it's quite good.

                  KroMignonK 1 Reply Last reply
                  0
                  • J jenya7

                    @KroMignon
                    I see. So time sensitive tasks I can run with QTimer and set zero delay? Actually it's quite good.

                    KroMignonK Offline
                    KroMignonK Offline
                    KroMignon
                    wrote on last edited by
                    #9

                    @jenya7 said in Non blocking console reading.:

                    I see. So time sensitive tasks I can run with QTimer and set zero delay? Actually it's quite good.

                    I am not sure to right understand your question.
                    First, Qt is not a realtime framework.
                    You can defined a QTimer instance with a given interval and so ensure a give slot will be call every XXX milliseconds.
                    You can used QTimer::singleShot() to do it once.

                    All this do, is emitting a signal which will be handle by the event queue, which will call the attached slot(s)/lambda(s)/functor(s) attached to it.
                    That's all the magic behind Qt signals/slots.
                    This is why not blocking the event queue is vital for Qt applications.

                    It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

                    J 1 Reply Last reply
                    1
                    • KroMignonK KroMignon

                      @jenya7 said in Non blocking console reading.:

                      I see. So time sensitive tasks I can run with QTimer and set zero delay? Actually it's quite good.

                      I am not sure to right understand your question.
                      First, Qt is not a realtime framework.
                      You can defined a QTimer instance with a given interval and so ensure a give slot will be call every XXX milliseconds.
                      You can used QTimer::singleShot() to do it once.

                      All this do, is emitting a signal which will be handle by the event queue, which will call the attached slot(s)/lambda(s)/functor(s) attached to it.
                      That's all the magic behind Qt signals/slots.
                      This is why not blocking the event queue is vital for Qt applications.

                      J Offline
                      J Offline
                      jenya7
                      wrote on last edited by
                      #10

                      @KroMignon
                      One more question. If I install several timers - does it runs in separate threads? Do I have to worry about cross thread collisions?

                      int main(int argc, char *argv[])
                      {
                          QCoreApplication a(argc, argv);
                      
                          QTimer timer1;
                          QObject::connect(&timer1, &QTimer::timeout,  Func1);
                          timer1.start(1);
                      
                          QTimer timer2;
                          QObject::connect(&timer2, &QTimer::timeout,  Func2);
                          timer2.start(10);
                      
                          return a.exec();
                      }
                      
                      
                      JonBJ 1 Reply Last reply
                      0
                      • J jenya7

                        @KroMignon
                        One more question. If I install several timers - does it runs in separate threads? Do I have to worry about cross thread collisions?

                        int main(int argc, char *argv[])
                        {
                            QCoreApplication a(argc, argv);
                        
                            QTimer timer1;
                            QObject::connect(&timer1, &QTimer::timeout,  Func1);
                            timer1.start(1);
                        
                            QTimer timer2;
                            QObject::connect(&timer2, &QTimer::timeout,  Func2);
                            timer2.start(10);
                        
                            return a.exec();
                        }
                        
                        
                        JonBJ Offline
                        JonBJ Offline
                        JonB
                        wrote on last edited by JonB
                        #11

                        @jenya7
                        No they do not run in separate threads. In Qt only one timer signal is issued at a time, the next one cannot happen until any slot(s) attached to the first one have returned. At around 10 seconds both of your timers will timeout, in undefined order.

                        J.HilkJ 1 Reply Last reply
                        1
                        • JonBJ JonB

                          @jenya7
                          No they do not run in separate threads. In Qt only one timer signal is issued at a time, the next one cannot happen until any slot(s) attached to the first one have returned. At around 10 seconds both of your timers will timeout, in undefined order.

                          J.HilkJ Offline
                          J.HilkJ Offline
                          J.Hilk
                          Moderators
                          wrote on last edited by
                          #12

                          @JonB said in Non blocking console reading.:

                          In Qt only one timer signal is issued at a time, the next one cannot happen until any slot(s) attached to the first one have returned.

                          Normally!
                          There's a (Qt) way to break that, rather easily.


                          Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                          Q: What's that?
                          A: It's blue light.
                          Q: What does it do?
                          A: It turns blue.

                          JonBJ 1 Reply Last reply
                          1
                          • J.HilkJ J.Hilk

                            @JonB said in Non blocking console reading.:

                            In Qt only one timer signal is issued at a time, the next one cannot happen until any slot(s) attached to the first one have returned.

                            Normally!
                            There's a (Qt) way to break that, rather easily.

                            JonBJ Offline
                            JonBJ Offline
                            JonB
                            wrote on last edited by JonB
                            #13

                            @J-Hilk
                            That, it seems to me, is true for any Qt signals (certain code can cause another signal to be emitted while one is still being handled). However, I took the OP's question to mean if she just does some non-Qt processing in the slots.

                            In any case, even if the second timer signal is emitted while the first is still being handled, I don't see that is a threading issue (again, assuming, OP is not doing her own threading stuff).

                            1 Reply Last reply
                            1
                            • J Offline
                              J Offline
                              jenya7
                              wrote on last edited by jenya7
                              #14

                              I've experimented a bit, just to understand deeper

                              int main(int argc, char *argv[])
                              {
                                  QCoreApplication a(argc, argv);
                              
                                QFuture<void> future = QtConcurrent::run(&TerminalRead);
                              
                                while(1)
                                {
                                     DoSomething();
                                }
                              }
                              
                              __attribute__ ((noreturn)) void TerminalRead()
                              {
                                  while (1)
                                  {
                                      ch_ptr = fgets(cons_str, 256, stdin);
                                      if (ch_ptr != nullptr)
                                      {
                                          trimmed_str =  Trim(cons_str, TRIM_BOTH);
                                          COMPARSER_ParseCommand(trimmed_str);
                                      }
                                  }
                              }
                              

                              And it works quite well. I get non blocking input from console and parse it. And tasks run in the loop.
                              Is using QtConcurrent good practice? Does it creates a separate thread? Is it alternative to timers?

                              JonBJ 1 Reply Last reply
                              0
                              • J jenya7

                                I've experimented a bit, just to understand deeper

                                int main(int argc, char *argv[])
                                {
                                    QCoreApplication a(argc, argv);
                                
                                  QFuture<void> future = QtConcurrent::run(&TerminalRead);
                                
                                  while(1)
                                  {
                                       DoSomething();
                                  }
                                }
                                
                                __attribute__ ((noreturn)) void TerminalRead()
                                {
                                    while (1)
                                    {
                                        ch_ptr = fgets(cons_str, 256, stdin);
                                        if (ch_ptr != nullptr)
                                        {
                                            trimmed_str =  Trim(cons_str, TRIM_BOTH);
                                            COMPARSER_ParseCommand(trimmed_str);
                                        }
                                    }
                                }
                                

                                And it works quite well. I get non blocking input from console and parse it. And tasks run in the loop.
                                Is using QtConcurrent good practice? Does it creates a separate thread? Is it alternative to timers?

                                JonBJ Offline
                                JonBJ Offline
                                JonB
                                wrote on last edited by JonB
                                #15

                                @jenya7
                                Yes it creates a separate thread. That is one way of using blocking calls without blocking the main thread. I didn't want to complicate with that possibility earlier (but you seem to have dived right in there!).

                                Be aware: I'm not sure whether C runtime calls like fgets() are thread-safe if you use them, or other stdio, stuff in other threads. (Answer: it is not thread-safe, unless you are using some version/library which has been rewritten to be thread-safe.) You must also be careful what you do in COMPARSER_ParseCommand(), as that is running in its own thread.

                                J 1 Reply Last reply
                                1
                                • JonBJ JonB

                                  @jenya7
                                  Yes it creates a separate thread. That is one way of using blocking calls without blocking the main thread. I didn't want to complicate with that possibility earlier (but you seem to have dived right in there!).

                                  Be aware: I'm not sure whether C runtime calls like fgets() are thread-safe if you use them, or other stdio, stuff in other threads. (Answer: it is not thread-safe, unless you are using some version/library which has been rewritten to be thread-safe.) You must also be careful what you do in COMPARSER_ParseCommand(), as that is running in its own thread.

                                  J Offline
                                  J Offline
                                  jenya7
                                  wrote on last edited by
                                  #16

                                  @JonB
                                  With timers it works very well. I'm glad. Thank you.

                                  KroMignonK 1 Reply Last reply
                                  0
                                  • J jenya7

                                    @JonB
                                    With timers it works very well. I'm glad. Thank you.

                                    KroMignonK Offline
                                    KroMignonK Offline
                                    KroMignon
                                    wrote on last edited by
                                    #17

                                    @jenya7 said in Non blocking console reading.:

                                    With timers it works very well. I'm glad. Thank you.

                                    I don't think 'this works well'.
                                    It is horrible in terms of Qt code conformity.
                                    Please be consistent.
                                    If you want to use Qt for developing an application, then use it in the right way or you will only be frustrated because nothing will work as expected.

                                    Again and again do not use forever loops/ active waits with Qt if you want your application to work.

                                    It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

                                    J 1 Reply Last reply
                                    0
                                    • KroMignonK KroMignon

                                      @jenya7 said in Non blocking console reading.:

                                      With timers it works very well. I'm glad. Thank you.

                                      I don't think 'this works well'.
                                      It is horrible in terms of Qt code conformity.
                                      Please be consistent.
                                      If you want to use Qt for developing an application, then use it in the right way or you will only be frustrated because nothing will work as expected.

                                      Again and again do not use forever loops/ active waits with Qt if you want your application to work.

                                      J Offline
                                      J Offline
                                      jenya7
                                      wrote on last edited by jenya7
                                      #18

                                      @KroMignon
                                      I have a discover function - it runs through all sensors and detects who is alive - I see no way but to iterate all sensors in a loop. It looks like

                                      discover_state = DISC_ST_START;
                                      
                                          printf("Discovering...\n");
                                      
                                           while (done == 0)
                                           {
                                              switch (discover_state)
                                              {
                                                  case DISC_ST_START:
                                                      data[3] = static_cast<char>(MSG_OPCODE_WHO_IS);
                                                      data[2] = static_cast<char>(idx); //to  a slave
                                      
                                                      //reset for the next sensor
                                                      new_message_flag = 0;
                                                      timer.restart();
                                      
                                                     UDP_Send(data, sys_params.broadcast_ip, sys_params.remote_port);
                                      
                                                      discover_state = DISC_ST_WAIT;
                                                  break;
                                                  case DISC_ST_WAIT:
                                                      if (new_message_flag)
                                                      {
                                                          printf("Discovered sensor ID: %d\n", idx);
                                      
                                                          discover_state = DISC_ST_NEXT;
                                                      }
                                                      else
                                                      {
                                                          millisec = timer.elapsed();
                                      
                                                          if (millisec > SENS_RESPONSE_TIME)
                                                             discover_state = DISC_ST_NEXT;
                                                      }
                                                  break;
                                                  case DISC_ST_NEXT:
                                                      idx++;
                                                      if (idx >= count || idx >= 254)
                                                          done = 1;
                                                      else
                                                          discover_state = DISC_ST_START;
                                                  break;
                                              }
                                          }
                                           printf("Done.\n");
                                      

                                      May I get rid of the loop?

                                      JonBJ 1 Reply Last reply
                                      0
                                      • J jenya7

                                        @KroMignon
                                        I have a discover function - it runs through all sensors and detects who is alive - I see no way but to iterate all sensors in a loop. It looks like

                                        discover_state = DISC_ST_START;
                                        
                                            printf("Discovering...\n");
                                        
                                             while (done == 0)
                                             {
                                                switch (discover_state)
                                                {
                                                    case DISC_ST_START:
                                                        data[3] = static_cast<char>(MSG_OPCODE_WHO_IS);
                                                        data[2] = static_cast<char>(idx); //to  a slave
                                        
                                                        //reset for the next sensor
                                                        new_message_flag = 0;
                                                        timer.restart();
                                        
                                                       UDP_Send(data, sys_params.broadcast_ip, sys_params.remote_port);
                                        
                                                        discover_state = DISC_ST_WAIT;
                                                    break;
                                                    case DISC_ST_WAIT:
                                                        if (new_message_flag)
                                                        {
                                                            printf("Discovered sensor ID: %d\n", idx);
                                        
                                                            discover_state = DISC_ST_NEXT;
                                                        }
                                                        else
                                                        {
                                                            millisec = timer.elapsed();
                                        
                                                            if (millisec > SENS_RESPONSE_TIME)
                                                               discover_state = DISC_ST_NEXT;
                                                        }
                                                    break;
                                                    case DISC_ST_NEXT:
                                                        idx++;
                                                        if (idx >= count || idx >= 254)
                                                            done = 1;
                                                        else
                                                            discover_state = DISC_ST_START;
                                                    break;
                                                }
                                            }
                                             printf("Done.\n");
                                        

                                        May I get rid of the loop?

                                        JonBJ Offline
                                        JonBJ Offline
                                        JonB
                                        wrote on last edited by
                                        #19

                                        @jenya7
                                        You are asking a very different question here.

                                        Let's go back to the original blocking/non-blocking input from console/terminal.

                                        There are only two choices for how to approach:

                                        • The single-threaded (Qt) way. Cannot use a while (true) loop, and cannot be done with a blocking call like fgets(). You would either have to pursue the links I posted, or change over to a QApplication instead of QCoreApplication.

                                        • The multi-threaded (not-really-Qt) way you posted. Use a thread. That can allow fgets(), and also while (true): they both block, but it's OK because they are in a thread.

                                        J 1 Reply Last reply
                                        0
                                        • JonBJ JonB

                                          @jenya7
                                          You are asking a very different question here.

                                          Let's go back to the original blocking/non-blocking input from console/terminal.

                                          There are only two choices for how to approach:

                                          • The single-threaded (Qt) way. Cannot use a while (true) loop, and cannot be done with a blocking call like fgets(). You would either have to pursue the links I posted, or change over to a QApplication instead of QCoreApplication.

                                          • The multi-threaded (not-really-Qt) way you posted. Use a thread. That can allow fgets(), and also while (true): they both block, but it's OK because they are in a thread.

                                          J Offline
                                          J Offline
                                          jenya7
                                          wrote on last edited by
                                          #20

                                          @JonB
                                          Thank you. I have to process all this information. :)

                                          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