A way to destroy “thread” class

前端 未结 8 1261
甜味超标
甜味超标 2021-02-06 18:22

Here is a skeleton of my thread class:

class MyThread {
public:
   virutal ~MyThread();

   // will start thread with svc() as thread entry point
   void start()         


        
8条回答
  •  死守一世寂寞
    2021-02-06 18:55

    Considering your additional requirements posted as comment to Checkers' reply (which is the most straightforward way to do that):

    I agree that join in DTor is problematic for various reasons. But from that the lifetime of your thread object is unrelated to the lifetime of the OS thread object.


    First, you need to separate the data the thread uses from the thread object itself. They are distinct entities with distinct lifetime requirements.

    One approach is to make the data refcounted, and have any thread that wants to access it hold a strong reference to the data. This way, no thread will suddenly grab into the void, but the data will be destroyed as soon as noone touches it anymore.


    Second, about the thread object being destroyed when the thread joins:
    I am not sure if this is a good idea. The thread object is normally a way to query the state of a thread - but with a thread object that dies as soon as the thread finishes, noone can tell you wether the thread finished.

    Generally, I'd completely decouple the lifetime of the thread object from the lifetime of the OS thread: Destroying your thread object should not affect the thread itself. I see two basic approaches to this:

    1. Thread Handle Object - reference counted again, returned by thread creator, can be released as early as one likes without affecting the OS thread. It would expose methods such as Join, IsFinished, and can give access to the thread shared data.

    (If the thread object holds relevant execution state, the threafFunc itself could hold a reference to it, thereby ensuring the instance won't be released before the thread ends)

    1. Thin Wrapper - You simply create a temporary around an OS thread handle. You could not hold additional state for the thread easily, but it might be just enough to make it work: At any place, you can turn an OS thread handle into an thread object. The majority of communication - e.g. telling the thread to terminate - would be via the shared data.

    For your code example, this means: separate the start() from the svc()

    You'd roughly work with this API (XxxxPtr could be e.g. boost::shared_ptr):

    class Thread
    {
       public:
         bool IsFinished();
         void Join();
         bool TryJoin(long timeout); 
    
         WorkerPtr GetWorker();
    
         static ThreadPtr Start(WorkerPtr worker); // creates the thread
    };
    
    
    class Worker
    {
    private:
       virtual void Svc() = 0;
    
       friend class Thread; // so thread can run Svc()
    }
    

    Worker could contain a ThreadPtr itself, giving you a guarantee that the thread object exists during execution of Svc(). If multiple threads are allowed to work on the same data, this would have to be a thread list. Otherwise, Thread::Start would have to reject Workers that are already associated with a thread.


    Motivation: What to do with rogue threads that block?
    Assuming a thread fails to terminate within time for one reason or another, even though you told it to. You simply have three choices:

    • Deadlock, your applicaiton hangs. That usually happens if you join in the destructor.
    • Violently terminate the thread. That's potentially a violent termination of the app.
    • Let the thread run to completion on it's own data - you can notify the user, who can safely save & exit. Or you simply let the rogue thread dance on it's own copy of the data (not reference by the main thread anymore) until it completes.

提交回复
热议问题