Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Why does decoupling from random signal fix QML binding loop?

Why does decoupling from random signal fix QML binding loop?

Scheduled Pinned Locked Moved Solved QML and Qt Quick
propertiesqml
8 Posts 3 Posters 1.5k 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.
  • S Offline
    S Offline
    stan.m
    wrote on 20 Nov 2018, 07:36 last edited by
    #1

    I've been trying to address a defect that breaks my QML UI and the defect went away... why???

    I have C++ code that monitors hardware readings that can change as often as every millisecond, but seldom changes more than 10 times in a second. The value is exposed as a QString property which is displayed in QML. After a while (usually hours) I get a message "binding loop detected" and my program becomes unstable.

    I hypothesized that occasionally multiple signals come in very close together and are falsely detected as a "binding loop" but I have not read anything discussing this. I de-coupled the changes in the hardware reading from the property by storing the new value and polling the value 60-times-per-second and displaying changes. Now my code is stable.

    Why does this work? Why is QML making a false "binding loop"? Is this a problem when reading hardware?

    R 1 Reply Last reply 20 Nov 2018, 07:39
    0
    • S stan.m
      22 Nov 2018, 02:42

      @J.Hilk I checked the Qt source code: two separate "changed" signals cannot trigger a "binding loop" message.

      In Qt’s qqmlbinding.cpp source code, the QQmlBinding::update() function checks an "updatingFlag" before printing the "binding loop" message and returning or continues, setting the "updatingFlag" before evaluating the binding then clears the "updatingFlag" before exiting the function.

      My solution works, but yours is better. My solution can result in multiple signals being added to the event queue if the UI thread pauses due to an operation taking too long. Your solution prevents that.

      The only addition I would make is to use a std::atomic for the data to address the undefined behavior of data being “written to” and “read from” by two different threads.

      I still do not know what causes the “binding loop” message, but I know better what it is not. It is not just a binding loop issue. Attaching a debugger, I see dozens of first chance exceptions before the “binding loop” message. I missed these before because they were not logged. Reviewing logs, this occurs after hours of continuous operation or never occurs even after weeks of operation.

      It is not a thread-safety issue in regards to the data (It was a thread-safety issue -- see response below.) It is not a case of the Event queue overflowing (it has happened with 137-8000+ items on the queue and my solution works correctly with 2 million items on the Event queue).

      I can only reproduce it if the real time change is allowed to add signals to the UI thread’s event queue. I can add change signals 62 times per second indefinitely, 82 per second runs out of memory eventually as the Event queue fills up (avoided with the Timer solution).

      Best practices:

      • near real-time hardware changes should be polled instead of allowed to each add a signal on the UI thread’s event queue.
      • a Timer (on the UI thread) prevents multiple change signals for the same QObject being processed in the same Eventloop cycle.

      Where to learn this aside from ICS webinars? (and I’m sure KDAB teaches this too.)

      S Offline
      S Offline
      stan.m
      wrote on 3 Dec 2018, 19:04 last edited by
      #8

      @stan.m The root cause was a thread-safety problem; data was read by the main thread at the same time that it was written by another thread. Specifically, the C++ getter for the QString "value" property was called at the same time that the value was written. Other data was written and read at the same time, but their types write as an atomic operation on the ARM processor. The data that caused the problem was of type: QString.

      A QString object's member data is a heap pointer to the 16-bit unicode array. When written and read simultaneously, the C++ getter passes a corrupted pointer into the QML runtime. As I wrote before, the "binding loop" warning came after many of these "first-chance" exceptions and had nothing to do with a true binding loop.

      The first-chance exception occurred when two value changes occurred back-to-back and the QML runtime called the C++ getter to retrieve the value at the same time that the second change was written.

      My initial "fix" worked because polling the value every 100ms allowed the first change propagate to QML long before the next change comes in.

      I since have revised the code to use a mutex to prevent writing and reading simultaneously.

      1 Reply Last reply
      0
      • S stan.m
        20 Nov 2018, 07:36

        I've been trying to address a defect that breaks my QML UI and the defect went away... why???

        I have C++ code that monitors hardware readings that can change as often as every millisecond, but seldom changes more than 10 times in a second. The value is exposed as a QString property which is displayed in QML. After a while (usually hours) I get a message "binding loop detected" and my program becomes unstable.

        I hypothesized that occasionally multiple signals come in very close together and are falsely detected as a "binding loop" but I have not read anything discussing this. I de-coupled the changes in the hardware reading from the property by storing the new value and polling the value 60-times-per-second and displaying changes. Now my code is stable.

        Why does this work? Why is QML making a false "binding loop"? Is this a problem when reading hardware?

        R Offline
        R Offline
        raven-worx
        Moderators
        wrote on 20 Nov 2018, 07:39 last edited by
        #2

        @stan.m
        you can't expect serious help without showing a single line of code where your binding loop might be.

        --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
        If you have a question please use the forum so others can benefit from the solution in the future

        S 1 Reply Last reply 20 Nov 2018, 17:22
        0
        • R raven-worx
          20 Nov 2018, 07:39

          @stan.m
          you can't expect serious help without showing a single line of code where your binding loop might be.

          S Offline
          S Offline
          stan.m
          wrote on 20 Nov 2018, 17:22 last edited by
          #3

          @raven-worx Here's the error:
          WARNING QtUI qrc:////Screens/Status/TransducerSummary.qml:12:19: QML Text: Binding loop detected for property "text"

          Here's minimum QML code that will show the first binding loop message after hours of continuous operation:

          Column {
              Rectangle {
                  width: 100; height: 40
                  color: ma3.pressed ? 'bluesteel' : 'darkgray'
          
                  Text { // <- error message points to this line
                      anchors.fill: parent
                      font { bold: true; pixelSize: 24 }
                      horizontalAlignment: Text.AlignHCenter
                      verticalAlignment: Text.AlignVCenter
                      color: 'white'
                      text: PressureTransducer.value
                  }
          
                  MouseArea { id: ma3; anchors.fill: parent; onClicked: rate.decrement() }
              }
          }
          
          R S J 3 Replies Last reply 20 Nov 2018, 18:26
          0
          • S stan.m
            20 Nov 2018, 17:22

            @raven-worx Here's the error:
            WARNING QtUI qrc:////Screens/Status/TransducerSummary.qml:12:19: QML Text: Binding loop detected for property "text"

            Here's minimum QML code that will show the first binding loop message after hours of continuous operation:

            Column {
                Rectangle {
                    width: 100; height: 40
                    color: ma3.pressed ? 'bluesteel' : 'darkgray'
            
                    Text { // <- error message points to this line
                        anchors.fill: parent
                        font { bold: true; pixelSize: 24 }
                        horizontalAlignment: Text.AlignHCenter
                        verticalAlignment: Text.AlignVCenter
                        color: 'white'
                        text: PressureTransducer.value
                    }
            
                    MouseArea { id: ma3; anchors.fill: parent; onClicked: rate.decrement() }
                }
            }
            
            R Offline
            R Offline
            raven-worx
            Moderators
            wrote on 20 Nov 2018, 18:26 last edited by
            #4

            @stan.m
            and the value property of PressureTransducer is somehow dependent on the text property?

            --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
            If you have a question please use the forum so others can benefit from the solution in the future

            1 Reply Last reply
            0
            • S stan.m
              20 Nov 2018, 17:22

              @raven-worx Here's the error:
              WARNING QtUI qrc:////Screens/Status/TransducerSummary.qml:12:19: QML Text: Binding loop detected for property "text"

              Here's minimum QML code that will show the first binding loop message after hours of continuous operation:

              Column {
                  Rectangle {
                      width: 100; height: 40
                      color: ma3.pressed ? 'bluesteel' : 'darkgray'
              
                      Text { // <- error message points to this line
                          anchors.fill: parent
                          font { bold: true; pixelSize: 24 }
                          horizontalAlignment: Text.AlignHCenter
                          verticalAlignment: Text.AlignVCenter
                          color: 'white'
                          text: PressureTransducer.value
                      }
              
                      MouseArea { id: ma3; anchors.fill: parent; onClicked: rate.decrement() }
                  }
              }
              
              S Offline
              S Offline
              stan.m
              wrote on 20 Nov 2018, 20:34 last edited by
              #5

              @stan.m This is Qt 5.6.3 on ARM on WEC2013.

              1 Reply Last reply
              0
              • S stan.m
                20 Nov 2018, 17:22

                @raven-worx Here's the error:
                WARNING QtUI qrc:////Screens/Status/TransducerSummary.qml:12:19: QML Text: Binding loop detected for property "text"

                Here's minimum QML code that will show the first binding loop message after hours of continuous operation:

                Column {
                    Rectangle {
                        width: 100; height: 40
                        color: ma3.pressed ? 'bluesteel' : 'darkgray'
                
                        Text { // <- error message points to this line
                            anchors.fill: parent
                            font { bold: true; pixelSize: 24 }
                            horizontalAlignment: Text.AlignHCenter
                            verticalAlignment: Text.AlignVCenter
                            color: 'white'
                            text: PressureTransducer.value
                        }
                
                        MouseArea { id: ma3; anchors.fill: parent; onClicked: rate.decrement() }
                    }
                }
                
                J Offline
                J Offline
                J.Hilk
                Moderators
                wrote on 20 Nov 2018, 20:40 last edited by J.Hilk
                #6

                @stan.m
                I‘m unsure how exactly the binding loop detection works, but my guess would be, the changed signal of ‚‘PressureTransducer.value‘ es emitted more than once during one eventloop cycle and actually changes too

                A workaround could be a single shot timer with an intervall of 0, that on timeout emit the changed signal. When the value changes, you simply reset the timer.
                That would guarantee a single changed signal per eventloop cycle


                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.

                S 1 Reply Last reply 22 Nov 2018, 02:42
                1
                • J J.Hilk
                  20 Nov 2018, 20:40

                  @stan.m
                  I‘m unsure how exactly the binding loop detection works, but my guess would be, the changed signal of ‚‘PressureTransducer.value‘ es emitted more than once during one eventloop cycle and actually changes too

                  A workaround could be a single shot timer with an intervall of 0, that on timeout emit the changed signal. When the value changes, you simply reset the timer.
                  That would guarantee a single changed signal per eventloop cycle

                  S Offline
                  S Offline
                  stan.m
                  wrote on 22 Nov 2018, 02:42 last edited by stan.m 12 Mar 2018, 19:06
                  #7

                  @J.Hilk I checked the Qt source code: two separate "changed" signals cannot trigger a "binding loop" message.

                  In Qt’s qqmlbinding.cpp source code, the QQmlBinding::update() function checks an "updatingFlag" before printing the "binding loop" message and returning or continues, setting the "updatingFlag" before evaluating the binding then clears the "updatingFlag" before exiting the function.

                  My solution works, but yours is better. My solution can result in multiple signals being added to the event queue if the UI thread pauses due to an operation taking too long. Your solution prevents that.

                  The only addition I would make is to use a std::atomic for the data to address the undefined behavior of data being “written to” and “read from” by two different threads.

                  I still do not know what causes the “binding loop” message, but I know better what it is not. It is not just a binding loop issue. Attaching a debugger, I see dozens of first chance exceptions before the “binding loop” message. I missed these before because they were not logged. Reviewing logs, this occurs after hours of continuous operation or never occurs even after weeks of operation.

                  It is not a thread-safety issue in regards to the data (It was a thread-safety issue -- see response below.) It is not a case of the Event queue overflowing (it has happened with 137-8000+ items on the queue and my solution works correctly with 2 million items on the Event queue).

                  I can only reproduce it if the real time change is allowed to add signals to the UI thread’s event queue. I can add change signals 62 times per second indefinitely, 82 per second runs out of memory eventually as the Event queue fills up (avoided with the Timer solution).

                  Best practices:

                  • near real-time hardware changes should be polled instead of allowed to each add a signal on the UI thread’s event queue.
                  • a Timer (on the UI thread) prevents multiple change signals for the same QObject being processed in the same Eventloop cycle.

                  Where to learn this aside from ICS webinars? (and I’m sure KDAB teaches this too.)

                  S 1 Reply Last reply 3 Dec 2018, 19:04
                  1
                  • S stan.m
                    22 Nov 2018, 02:42

                    @J.Hilk I checked the Qt source code: two separate "changed" signals cannot trigger a "binding loop" message.

                    In Qt’s qqmlbinding.cpp source code, the QQmlBinding::update() function checks an "updatingFlag" before printing the "binding loop" message and returning or continues, setting the "updatingFlag" before evaluating the binding then clears the "updatingFlag" before exiting the function.

                    My solution works, but yours is better. My solution can result in multiple signals being added to the event queue if the UI thread pauses due to an operation taking too long. Your solution prevents that.

                    The only addition I would make is to use a std::atomic for the data to address the undefined behavior of data being “written to” and “read from” by two different threads.

                    I still do not know what causes the “binding loop” message, but I know better what it is not. It is not just a binding loop issue. Attaching a debugger, I see dozens of first chance exceptions before the “binding loop” message. I missed these before because they were not logged. Reviewing logs, this occurs after hours of continuous operation or never occurs even after weeks of operation.

                    It is not a thread-safety issue in regards to the data (It was a thread-safety issue -- see response below.) It is not a case of the Event queue overflowing (it has happened with 137-8000+ items on the queue and my solution works correctly with 2 million items on the Event queue).

                    I can only reproduce it if the real time change is allowed to add signals to the UI thread’s event queue. I can add change signals 62 times per second indefinitely, 82 per second runs out of memory eventually as the Event queue fills up (avoided with the Timer solution).

                    Best practices:

                    • near real-time hardware changes should be polled instead of allowed to each add a signal on the UI thread’s event queue.
                    • a Timer (on the UI thread) prevents multiple change signals for the same QObject being processed in the same Eventloop cycle.

                    Where to learn this aside from ICS webinars? (and I’m sure KDAB teaches this too.)

                    S Offline
                    S Offline
                    stan.m
                    wrote on 3 Dec 2018, 19:04 last edited by
                    #8

                    @stan.m The root cause was a thread-safety problem; data was read by the main thread at the same time that it was written by another thread. Specifically, the C++ getter for the QString "value" property was called at the same time that the value was written. Other data was written and read at the same time, but their types write as an atomic operation on the ARM processor. The data that caused the problem was of type: QString.

                    A QString object's member data is a heap pointer to the 16-bit unicode array. When written and read simultaneously, the C++ getter passes a corrupted pointer into the QML runtime. As I wrote before, the "binding loop" warning came after many of these "first-chance" exceptions and had nothing to do with a true binding loop.

                    The first-chance exception occurred when two value changes occurred back-to-back and the QML runtime called the C++ getter to retrieve the value at the same time that the second change was written.

                    My initial "fix" worked because polling the value every 100ms allowed the first change propagate to QML long before the next change comes in.

                    I since have revised the code to use a mutex to prevent writing and reading simultaneously.

                    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