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. QSharedPointer thread safety?

QSharedPointer thread safety?

Scheduled Pinned Locked Moved Unsolved General and Desktop
3 Posts 3 Posters 1.1k 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.
  • T Offline
    T Offline
    thierryhenry14
    wrote on last edited by
    #1

    Let's say I have this code

    
    struct QuestDetails {
      QString adventurerId;
      QMap<QString,QVariant> questParams;
      SomeCustomType custom;
    }
    
    //running on main thread
    class GameManager {
    signals:
      ...
      void QuestStarted(const QSharedPointer<QuestDetails>& questDetails);
    	
    private:
      void dosomething() {
        QMap<QString,QVariant> newQuestParams;
        newQuestParams["target"] = "Deckard";
        newQuestParams["deadline"] = QDateTime::currentDateTime().addDays(1);
        auto questDetails = QSharedPointer<QuestDetails>(new QuestDetails);
        questDetails->adventurerId = "Cloud";
        questDetails->questParams = newQuestParams;
        questDetails->custom = SomeCustomType("ABC", 123, "moredata");
        emit QuestStarted(questDetails);
    }
    };
    
    //running on thread #2
    class Adventurer {
    public slots:
      void onQuestStarted(const QSharedPointer<QuestDetails>& questDetails) {
        qDebug() << questDetails->questParams;
      }
    };
    
    //running on thread #3
    class EvilSpy {
      void onQuestStarted(const QSharedPointer<QuestDetails>& questDetails) {
        QMap<QString,QVariant> modifiedMap  = questDetails->questParams;
        modifiedMap["target"] = "Deckard's wife";
        modifiedMap["extra-key"] = 123;
        qDebug() << "my modified map:" << modifiedMap;
      }
    };
    

    Question 1: looking at just GameManager and Adventurer, is there anything wrong with this? The doc says "in general, a given QSharedPointer or QWeakPointer object cannot be accessed by multiple threads at the same time without synchronization." I don't want to use mutexes, I just want the QuestDetails to be deleted safely when all slots have finished handling it and reference counter drops to 0. Let's say Adventurer thread is doing a long calculation at the time the main thread is emitting QuestStarted. Is there a risk of the QSharedPointer counter dropping to 0 right after emitting and deleting the QuestDetails by the time the Adventurer thread is available and begins processing that signal?

    assuming question 1 is safe...then Question 2: is there anything wrong with what the EvilSpy class is doing? From what I've read about implicit containers, the questParams QMap will be fully copied during the non-const call "modifiedMap["extra-key"] = 123". The original is never modified. According to the doc "implicit shared classes can safely be copied across threads, like any other value classes", so this is fine, right?

    Keeping in mind, I have no intention of having my slots running on multiple threads modify the objects given as the signal argument. They are always accessed read-only. Is this enough to ensure thread safety?

    jsulmJ 1 Reply Last reply
    0
    • Christian EhrlicherC Online
      Christian EhrlicherC Online
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on last edited by
      #2

      The ref counting of a shared pointer is thread-safe so there can't be a double delete. Therefore what you're doing is correct as long as you don't modify your data after the emit.

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      1 Reply Last reply
      1
      • T thierryhenry14

        Let's say I have this code

        
        struct QuestDetails {
          QString adventurerId;
          QMap<QString,QVariant> questParams;
          SomeCustomType custom;
        }
        
        //running on main thread
        class GameManager {
        signals:
          ...
          void QuestStarted(const QSharedPointer<QuestDetails>& questDetails);
        	
        private:
          void dosomething() {
            QMap<QString,QVariant> newQuestParams;
            newQuestParams["target"] = "Deckard";
            newQuestParams["deadline"] = QDateTime::currentDateTime().addDays(1);
            auto questDetails = QSharedPointer<QuestDetails>(new QuestDetails);
            questDetails->adventurerId = "Cloud";
            questDetails->questParams = newQuestParams;
            questDetails->custom = SomeCustomType("ABC", 123, "moredata");
            emit QuestStarted(questDetails);
        }
        };
        
        //running on thread #2
        class Adventurer {
        public slots:
          void onQuestStarted(const QSharedPointer<QuestDetails>& questDetails) {
            qDebug() << questDetails->questParams;
          }
        };
        
        //running on thread #3
        class EvilSpy {
          void onQuestStarted(const QSharedPointer<QuestDetails>& questDetails) {
            QMap<QString,QVariant> modifiedMap  = questDetails->questParams;
            modifiedMap["target"] = "Deckard's wife";
            modifiedMap["extra-key"] = 123;
            qDebug() << "my modified map:" << modifiedMap;
          }
        };
        

        Question 1: looking at just GameManager and Adventurer, is there anything wrong with this? The doc says "in general, a given QSharedPointer or QWeakPointer object cannot be accessed by multiple threads at the same time without synchronization." I don't want to use mutexes, I just want the QuestDetails to be deleted safely when all slots have finished handling it and reference counter drops to 0. Let's say Adventurer thread is doing a long calculation at the time the main thread is emitting QuestStarted. Is there a risk of the QSharedPointer counter dropping to 0 right after emitting and deleting the QuestDetails by the time the Adventurer thread is available and begins processing that signal?

        assuming question 1 is safe...then Question 2: is there anything wrong with what the EvilSpy class is doing? From what I've read about implicit containers, the questParams QMap will be fully copied during the non-const call "modifiedMap["extra-key"] = 123". The original is never modified. According to the doc "implicit shared classes can safely be copied across threads, like any other value classes", so this is fine, right?

        Keeping in mind, I have no intention of having my slots running on multiple threads modify the objects given as the signal argument. They are always accessed read-only. Is this enough to ensure thread safety?

        jsulmJ Offline
        jsulmJ Offline
        jsulm
        Lifetime Qt Champion
        wrote on last edited by
        #3

        @thierryhenry14 Signals/slots across threads use copies of parameters, even if you specify the parameters as references. So, it should be safe, as a copy of your shared pointer will be created as soon as you emit the signal.

        https://forum.qt.io/topic/113070/qt-code-of-conduct

        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