jeudi 16 septembre 2021

Is it right to use shared_ptr/raw pointer to shared an atomic between two interacted threads?

I have two class that follow this manner to encapsulate threads inside a C++ object.

class MyThreadClass
{
public:
   MyThreadClass() {/* empty */}
   virtual ~MyThreadClass() {/* empty */}

   /** Returns true if the thread was successfully started, false if there was an error starting the thread */
   bool StartInternalThread()
   {
      return (pthread_create(&_thread, NULL, InternalThreadEntryFunc, this) == 0);
   }

   /** Will not return until the internal thread has exited. */
   void WaitForInternalThreadToExit()
   {
      (void) pthread_join(_thread, NULL);
   }

protected:
   /** Implement this method in your subclass with the code you want your thread to run. */
   virtual void InternalThreadEntry() = 0;

private:
   static void * InternalThreadEntryFunc(void * This) {((MyThreadClass *)This)->InternalThreadEntry(); return NULL;}

   pthread_t _thread;
};

Now these i need the instances of these two class to do something together, generally, a instance of class B polling a flag and do its own job until the flag is set by class A:

class A : public MyThreadClass{
protected:
    virtual void InternalThreadEntry(){
        doSomething();
        flag.store(true);
        doOtherThing();
    }
private:
    std::atomic_bool& flag;
};
class B : public MyThreadClass{
protected:
    virtual void InternalThreadEntry(){
        do{
            doOwnJob();
            // thus cannot use condition variable
        }while(flag.load() == false);
        doOther();
    }
private:
    std::atomic_bool& flag;
};

Since the lifecycle of this two classes instances are bounded, i create a manager class to handle some shared variables instead of using global variable.

class Manager{
private:
    A a;
    B b;
    std::atomic_bool flag; // to shared between
};

Of course, these codes cannot be compiled, since the reference field must be be included in constructor's initialized list.

One of the ways to work around is to change class A/B's constructor signature to accept a reference to flag, since the flag lifecycle is bounded to these two class instances. However, this is not a valid choice since i am working on an existed code base, such change might involve massive code modification.

So it seems that i can only use a "setter" two set this flag field within each instance. And that makes the reference member declaration impossible. Intuitively, i think about using shared_ptr/raw_ptr to shared one flag between two class instances. But i wonder if this is "safe" manner or not? Or what is the better solution to deal with such situation?

Aucun commentaire:

Enregistrer un commentaire