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. Is it safe to use QClipboard in a background thread
Forum Updated to NodeBB v4.3 + New Features

Is it safe to use QClipboard in a background thread

Scheduled Pinned Locked Moved Solved General and Desktop
13 Posts 7 Posters 2.1k Views 5 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.
  • K Offline
    K Offline
    Karmo
    wrote on last edited by
    #1

    Hi,

    I noticed parsing clipboard content freezes my application for a moment, so I would like to do it in a background thread. Is it safe to do the following?

        QtConcurrent::run([=] { 
          auto text = QApplication::clipboard()->text().toUtf8();
          ...
        }); 
    

    I have verified it does work but could there be any thread-safety issues here?

    JonBJ 1 Reply Last reply
    0
    • VRoninV Offline
      VRoninV Offline
      VRonin
      wrote on last edited by
      #3

      Yeah, looking at the source it's pretty clear it's not thread safe

      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
      ~Napoleon Bonaparte

      On a crusade to banish setIndexWidget() from the holy land of Qt

      1 Reply Last reply
      1
      • mrjjM Offline
        mrjjM Offline
        mrjj
        Lifetime Qt Champion
        wrote on last edited by
        #2

        @Karmo
        Hi
        Well it doesn't say its thread-safe so I would grab the text outside the lambda
        and simply avoid any issues altogether.

        1 Reply Last reply
        1
        • VRoninV Offline
          VRoninV Offline
          VRonin
          wrote on last edited by
          #3

          Yeah, looking at the source it's pretty clear it's not thread safe

          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
          ~Napoleon Bonaparte

          On a crusade to banish setIndexWidget() from the holy land of Qt

          1 Reply Last reply
          1
          • K Karmo

            Hi,

            I noticed parsing clipboard content freezes my application for a moment, so I would like to do it in a background thread. Is it safe to do the following?

                QtConcurrent::run([=] { 
                  auto text = QApplication::clipboard()->text().toUtf8();
                  ...
                }); 
            

            I have verified it does work but could there be any thread-safety issues here?

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

            @Karmo
            Just to be clear: I assume you're saying retrieving the text via QApplication::clipboard()->text() is what's slow, not the UTF8 conversion? Just check by removing .toUtf8(). If by any chance it's the latter, you could pass QApplication::clipboard()->text() to the thread....

            1 Reply Last reply
            0
            • K Offline
              K Offline
              Karmo
              wrote on last edited by
              #5

              Thanks. I will then keep QApplication::clipboard()->text() in the UI thread and will try without the .toUtf8().

              1 Reply Last reply
              0
              • K Offline
                K Offline
                Karmo
                wrote on last edited by
                #6

                @JonB, it is not toUtf8() that is slow.

                  auto start = system_clock::now();
                  auto t = QApplication::clipboard()->text();
                  qDebug() << "  QApplication::clipboard()->text() took" << duration_cast<milliseconds>(system_clock::now() - start).count() << "ms";
                  auto text = t.toUtf8();
                  start = system_clock::now();
                  qDebug() << "  toUtf8() took" << duration_cast<milliseconds>(system_clock::now() - start).count() << "ms";
                

                While 9 times out of 10 QApplication::clipboard()->text() takes under 20 ms, sometimes it really hangs the UI.

                  QApplication::clipboard()->text() took 3622 ms
                  toUtf8() took 0 ms
                

                This was measured on Linux Mint 20 with Qt 5.13 (but did not see any difference in 5.15). On Windows same code was always fast. Maybe something specific to my system.

                JonBJ jeremy_kJ 2 Replies Last reply
                1
                • K Karmo

                  @JonB, it is not toUtf8() that is slow.

                    auto start = system_clock::now();
                    auto t = QApplication::clipboard()->text();
                    qDebug() << "  QApplication::clipboard()->text() took" << duration_cast<milliseconds>(system_clock::now() - start).count() << "ms";
                    auto text = t.toUtf8();
                    start = system_clock::now();
                    qDebug() << "  toUtf8() took" << duration_cast<milliseconds>(system_clock::now() - start).count() << "ms";
                  

                  While 9 times out of 10 QApplication::clipboard()->text() takes under 20 ms, sometimes it really hangs the UI.

                    QApplication::clipboard()->text() took 3622 ms
                    toUtf8() took 0 ms
                  

                  This was measured on Linux Mint 20 with Qt 5.13 (but did not see any difference in 5.15). On Windows same code was always fast. Maybe something specific to my system.

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

                  @Karmo
                  Yes, unfortunately I did suggest/suspect it would not be UTF-ing, under whatever circumstances youur system can take a long time to access the clipboard. 3.6 seconds is not good! Especially if the clipboard does just have text on it, not something like a 1GB pixmap! You may find it's slow if, say, it's the first time you have accessed the clipboard in the current session/boot, or since you put something new on it, with some initializations overhead, at a guess.

                  Given what the guys have said above about it not being thread-safe, you'll have a tricky decision about what you want to do....

                  1 Reply Last reply
                  0
                  • S Offline
                    S Offline
                    SimonSchroeder
                    wrote on last edited by
                    #8

                    Not being thread-safe means that you shouldn't access the QClipboard from several threads at once. Using QtConcurrent::run() can be problematic in these cases. Instead – if you really want to go down this route – I would suggest using QThread. If you don't overwrite QThread::run() it will just start an event loop. You can then easily queue lambdas into this thread:

                    QMetaObject::invokeMethod(QAbstractEventDispatcher::instance(thread), [=](){...}, Qt::QueuedConnection);
                    

                    This approach would make sure that access to the clipboard is synchronized.

                    However, there is something else to consider: usability! In general, it is the user triggering access to the clipboard. An then the user will expect a certain action on the clipboard to occur. When your program freezes it is an obvious sign that the user still has to wait for the operation to finish. Depending on the specific use case it might be confusing if the program signals that operations on the clipboard are done when this is not the case.

                    kshegunovK 1 Reply Last reply
                    0
                    • S SimonSchroeder

                      Not being thread-safe means that you shouldn't access the QClipboard from several threads at once. Using QtConcurrent::run() can be problematic in these cases. Instead – if you really want to go down this route – I would suggest using QThread. If you don't overwrite QThread::run() it will just start an event loop. You can then easily queue lambdas into this thread:

                      QMetaObject::invokeMethod(QAbstractEventDispatcher::instance(thread), [=](){...}, Qt::QueuedConnection);
                      

                      This approach would make sure that access to the clipboard is synchronized.

                      However, there is something else to consider: usability! In general, it is the user triggering access to the clipboard. An then the user will expect a certain action on the clipboard to occur. When your program freezes it is an obvious sign that the user still has to wait for the operation to finish. Depending on the specific use case it might be confusing if the program signals that operations on the clipboard are done when this is not the case.

                      kshegunovK Offline
                      kshegunovK Offline
                      kshegunov
                      Moderators
                      wrote on last edited by
                      #9

                      @SimonSchroeder said in Is it safe to use QClipboard in a background thread:

                      This approach would make sure that access to the clipboard is synchronized.

                      How?

                      Read and abide by the Qt Code of Conduct

                      S 1 Reply Last reply
                      0
                      • K Karmo

                        @JonB, it is not toUtf8() that is slow.

                          auto start = system_clock::now();
                          auto t = QApplication::clipboard()->text();
                          qDebug() << "  QApplication::clipboard()->text() took" << duration_cast<milliseconds>(system_clock::now() - start).count() << "ms";
                          auto text = t.toUtf8();
                          start = system_clock::now();
                          qDebug() << "  toUtf8() took" << duration_cast<milliseconds>(system_clock::now() - start).count() << "ms";
                        

                        While 9 times out of 10 QApplication::clipboard()->text() takes under 20 ms, sometimes it really hangs the UI.

                          QApplication::clipboard()->text() took 3622 ms
                          toUtf8() took 0 ms
                        

                        This was measured on Linux Mint 20 with Qt 5.13 (but did not see any difference in 5.15). On Windows same code was always fast. Maybe something specific to my system.

                        jeremy_kJ Offline
                        jeremy_kJ Offline
                        jeremy_k
                        wrote on last edited by
                        #10

                        @Karmo said in Is it safe to use QClipboard in a background thread:

                        While 9 times out of 10 QApplication::clipboard()->text() takes under 20 ms, sometimes it really hangs the UI.

                          QApplication::clipboard()->text() took 3622 ms
                          toUtf8() took 0 ms
                        

                        Keep in mind that clipboard operations can be interprocess communication. Is the clipboard manager or application that executed the copy operation blocked, paged out, running at particularly low priority, etc at the moment that the pasting application is executing?

                        This was measured on Linux Mint 20 with Qt 5.13 (but did not see any difference in 5.15). On Windows same code was always fast. Maybe something specific to my system.

                        Clipboard handling is mostly done by the QPA plugin. Different performance between platforms isn't a surprise.
                        QClipboard::text(Mode mode) calls QClipboard::mimeData(Mode mode), which then uses platform specific code.

                        As far as safely handling the clipboard in another thread, it's a QObject. The usual rules apply. It might work for a while to QObject::moveToThread() it to a worker thread. That means avoiding lots of code in Qt that expects the clipboard to be in the GUI thread, including the QGuiApplication destructor.

                        Windowing system permitting, you could spawn a worker process that does nothing but read the clipboard and then send it to the parent over a socket or other asynchronous channel. The delay between the user's request and providing data will still be present but doesn't need to block the UI. As @SimonSchroeder points out, this might be confusing for the user.

                        Asking a question about code? http://eel.is/iso-c++/testcase/

                        1 Reply Last reply
                        0
                        • K Offline
                          K Offline
                          Karmo
                          wrote on last edited by Karmo
                          #11

                          I reduced the amount of clipboard reading by listening to the dataChanged() signal instead of polling the data. Added benefit is usually nothing is updating on the screen right after clicking Copy, so the intermittent hang is barely noticeable. This is sufficient at the moment but I'll keep the suggestions in mind in case any problems arise.

                          1 Reply Last reply
                          3
                          • kshegunovK kshegunov

                            @SimonSchroeder said in Is it safe to use QClipboard in a background thread:

                            This approach would make sure that access to the clipboard is synchronized.

                            How?

                            S Offline
                            S Offline
                            SimonSchroeder
                            wrote on last edited by
                            #12

                            @kshegunov said in Is it safe to use QClipboard in a background thread:

                            This approach would make sure that access to the clipboard is synchronized.

                            How?

                            To be more specific: This synchronizes access to the clipboard for this single program, but not between programs. If all access to the clipboard is sent to the event queue of a single thread it is synchronized. The event queue will only handle one event after the other. Then it does not matter if QClipboard is thread-safe if only a single thread accesses it.

                            jeremy_kJ 1 Reply Last reply
                            0
                            • S SimonSchroeder

                              @kshegunov said in Is it safe to use QClipboard in a background thread:

                              This approach would make sure that access to the clipboard is synchronized.

                              How?

                              To be more specific: This synchronizes access to the clipboard for this single program, but not between programs. If all access to the clipboard is sent to the event queue of a single thread it is synchronized. The event queue will only handle one event after the other. Then it does not matter if QClipboard is thread-safe if only a single thread accesses it.

                              jeremy_kJ Offline
                              jeremy_kJ Offline
                              jeremy_k
                              wrote on last edited by
                              #13

                              @SimonSchroeder said in Is it safe to use QClipboard in a background thread:

                              @kshegunov said in Is it safe to use QClipboard in a background thread:

                              This approach would make sure that access to the clipboard is synchronized.

                              How?

                              To be more specific: This synchronizes access to the clipboard for this single program, but not between programs. If all access to the clipboard is sent to the event queue of a single thread it is synchronized. The event queue will only handle one event after the other. Then it does not matter if QClipboard is thread-safe if only a single thread accesses it.

                              Sending an application's clipboard access to a non-gui thread event loop doesn't alter the access for any Qt or 3rd party components, or the QPA plugin.

                              Asking a question about code? http://eel.is/iso-c++/testcase/

                              1 Reply Last reply
                              1
                              • JonBJ JonB referenced this topic

                              • Login

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