C++ “一种毁灭的方式”;“线程”;班

C++ “一种毁灭的方式”;“线程”;班,c++,multithreading,C++,Multithreading,以下是我的线程类的框架: class MyThread { public: virutal ~MyThread(); // will start thread with svc() as thread entry point void start() = 0; // derive class will specialize what the thread should do virtual void svc() = 0;

以下是我的线程类的框架:

class MyThread {
public:
   virutal ~MyThread();

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

   // derive class will specialize what the thread should do
   virtual void svc() = 0;                
};
在代码的某个地方,我创建了一个
MyThread
的实例,然后我想销毁它。 在本例中,调用了
MyThread~MyThread()
MyThread:svc()
仍在运行并使用对象的数据成员。因此,在继续使用析构函数之前,我需要一种礼貌地通知
MyThread:svc()
停止旋转的方法

销毁线程对象的可接受方式是什么

注意:我正在寻找平台无关的解决方案


UPD:很明显,问题的根源在于,表示线程和C++线程的C++对象之间没有关系。所以问题是:在对象的上下文中,有一种可接受的方法来使线程对象像普通C++对象一样行为,或者应该在不去处理它之前把它当作一个不寻常的对象(例如,我们应该调用Couthor)吗?

< P>在SVC方法

中你可能会有类似的事情。
while (alive){ //loops}
//free resources after while.
在析构函数中,可以将活动成员设置为false。或者,可以使用pleaseDie()方法将活动成员设置为false,并可以从外部调用该方法,请求线程实例停止处理

void
Thread::pleaseDie()
{

 this->alive = false;
}

通常,任何特定于操作系统的线程API都允许您“加入”线程。也就是说,在线程函数返回之前无限期地阻塞线程句柄

所以

  • 向线程函数发送返回信号(例如,通过将其循环中的标志设置为
    false
  • 加入线程,以确保实际线程在尝试删除线程对象之前终止
  • 然后,您可以继续销毁线程对象(您也可以加入析构函数,尽管有些人反对阻塞析构函数)
  • 我以前有过一个类似的“线程工作者”类和相应的“工作项”类的项目(a-la Java的
    thread
    Runnable
    ,除了线程不终止,而是等待一个新的
    Runnable
    对象被执行)

    最后,如果您加入一个单独的“shutdown”函数或析构函数,除了一个单独的函数更清楚一点之外,没有什么区别

  • 如果加入析构函数和线程块,则将无限期等待
  • 如果您加入一个单独的函数并阻塞一个线程,您将无限期地等待
  • 如果您分离线程并让它自己完成,它通常会阻止应用程序退出,所以您将无限期地等待

  • <> P>所以没有一种简单的方法使线程像普通C++对象那样运行,忽略它的OS线程语义,除非你能保证你的线程代码在被通知要这么做的时候几乎可以立即终止。,处理此任务和其他任务,如簿记、拥有线程句柄等。线程本身应以某种方式向线程管理器发出信号,表示其将终止,MyThreadMngr应具有Tom建议的循环


    这样的线程管理器类中可能会有更多的操作。

    您首先需要一种与线程通信的方式来告诉它关闭。执行此操作的最佳机制取决于svc()正在执行的操作。例如,如果它在消息队列上循环,则可以插入“请停止”否则,您可以简单地添加一个成员bool变量(并同步对该变量的访问),该变量由svc()定期检查,并由想要销毁该对象的线程设置。您可以向基类添加一个纯虚拟stop()函数,给实现者一个明确的信号,表明它必须实现svc()使其类“可运行”,并实现stop()使其“可停止”


    在请求线程停止后,您必须等待它退出,然后才能销毁对象。同样,有几种方法可以做到这一点。一种是使stop()函数阻塞。例如,它可以等待运行svc()的线程设置的“ok,I'm really stopped now”条件变量。或者,调用方可以“wait”在运行svc()的线程上。“等待”的方式取决于平台。

    考虑到您作为Checkers回复(这是 最简单的方法是:

    我同意,由于各种原因,加入DTor是有问题的。但是从这个角度来看,线程对象的生存期与OS线程对象的生存期无关


    首先,您需要将线程使用的数据与线程对象本身分离。它们是具有不同生存期要求的不同实体

    一种方法是使数据重新计数,并让任何想要访问它的线程持有对该数据的强引用。这样,没有线程会突然进入空白,但一旦没有人再接触它,数据就会被销毁


    第二,关于线程连接时正在销毁的线程对象:
    我不确定这是不是一个好主意。thread对象通常是查询线程状态的一种方法——但是如果thread对象在线程结束后立即死亡,没有人能告诉您线程是否结束

    通常,我会将thread对象的生存期与OS线程的生存期完全分离:销毁thread对象不应该影响线程本身。我看到了两种基本方法:

  • 线程句柄对象-线程创建者返回的再次计数的引用,可以在不影响操作系统线程的情况下尽早释放。它将公开方法,如
    Join
    IsFinished
    ,并可以访问线程共享数据
  • (如果thread对象持有相关的执行状态,threafFunc本身可以持有对它的引用,从而确保在线程结束之前不会释放实例)

  • 瘦包装器-您只需创建一个临时aro
    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()
    }
    
    pthread_kill(pthread_t thread, int sig);
    
    #include <pthread.h>
    #include <iostream>
    
    extern "C" void* startThread(void*);
    extern "C" void  shouldIexit(int sig);
    
    class Thread
    {
        public:
            Thread();
            virtual ~Thread();
        private:
            friend void* startThread(void*);
    
            void start();
            virtual void run() = 0;
    
            bool        running;
            pthread_t   thread;
    };
    
    
    // I have seen a lot of implementations use a static class method to do this.
    // DON'T. It is not portable. This is because the C++ ABI is not defined.
    //
    // It currently works on several compilers but will break if these compilers
    // change the ABI they use. To gurantee this to work you should use a
    // function that is declared as extern "C" this guarantees that the ABI is 
    // correct for the callback. (Note this is true for all C callback functions)
    void* startThread(void* data)
    {
        Thread* thread  = reinterpret_cast<Thread*>(data);
        thread->start();
    }
    void shouldIexit(int sig)
    {
        // You should not use std::cout in signal handler.
        // This is for Demo purposes only.
        std::cout << "Signal" << std::endl;
    
        signal(sig,shouldIexit);
        // The default handler would kill the thread.
        // But by returning you can continue your code where you left off.
        // Or by throwing you can cause the stack to unwind (if the exception is caught).
        // If you do not catch the exception it is implementation defined weather the
        // stack is unwound.
        throw int(3);  // use int for simplicity in demo
    }
    
    
    Thread::Thread()
        :running(true)
    {
        // Note starting the thread in the constructor means that the thread may
        // start before the derived classes constructor finishes. This may potentially
        // be a problem. It is started here to make the code succinct and the derived
        // class used has no constructor so it does not matter.
        if (pthread_create(&thread,NULL,startThread,this) != 0)
        {
            throw int(5); // use int for simplicity in demo.
        }
    }
    
    Thread::~Thread()
    {
        void*   ignore;
    
        running = false;
        pthread_kill(thread,SIGSEGV); // Tell thread it may want to exit.
        pthread_join(thread,&ignore); // Wait for it to finish.
    
        // Do NOT leave before thread has exited.
    
        std::cout << "Thread Object Destroyed" << std::endl;
    }
    
    void Thread::start()
    {
        while(running)
        {
            try
            {
                this->run();
            }
            catch(...)
            {}
        }
        std::cout << "Thread exiting" << std::endl;
    }
    class MyTestThread:public Thread
    {
        public:
            virtual void run()
            {
                // Unless the signal causes an exception
                // this loop will never exit.
                while(true)
                {
                    sleep(5);
                }
            }
    
    };
    
    struct Info
    {
         Info() {std::cout << "Info" << std::endl;}
        ~Info() {std::cout << "Done: The thread Should have exited before this" << std::endl;}
    };
    
    int main()
    {
        signal(SIGSEGV,shouldIexit);
    
        Info                info;
        MyTestThread        test;
    
        sleep(4);
        std::cout << "Exiting About to Exit" << std::endl;
    
    }
    
    
    > ./a.exe
    Info
    Exiting About to Exit
    Signal
    Thread exiting
    Thread Object Destroyed
    Done: The thread Should have exited before this
    >
    
    while(isRunning())
    {
         ... thread implementation ...
    }
    
    class MyThread { 
    public: 
       virutal ~MyThread(); 
    
       // will be called when starting a thread, 
       // could do some initial operations 
       virtual bool OnStart() = 0;  
    
       // will be called when stopping a thread, say calling join().
       virtual bool OnStop() = 0;
    
       // derive class will specialize what the thread should do, 
       // say the thread loop such as 
       // while (bRunning) {
       //    do the job.
       // } 
       virtual int OnRun() = 0;                 
    }; 
    
        class IThread
        {
        public:
            virtual API ~IThread() {}
    
            /* The real destructor. */
            virtual void Destroy(void) = 0;
    
            /* Starts this thread, it will call MyThread::OnStart() 
                 * and then call MyThread::OnRun() just after created 
             *   the thread. */
            virtual bool Start(void) = 0;
    
            /* Stops a thread. will call MyThread::OnStop(). */
            virtual void Stop(void) = 0;
    
            /* If Wait() called, thread won't call MyThread::OnStop().
             * If could, it returns the value of MyThread::OnRun()
             *   returned */
            virtual int Wait(void) = 0;
    
            /* your staff */
            virtual MyThread * Command(void) = 0;
    
        };
    
    /* The interface to create a thread */
    extern IThread * ThrdCreate(MyThread *p);
    
    http://effoaddon.googlecode.com/svn/trunk/devel/effo/codebase/addons/thrd/include/thrd_i.h
    
    class ThreadLoop : public MyThread
    {
    private:
       bool m_bRunning;
    public:
       virtual bool OnStart() { m_bRunning = true; }  
    
       virtual bool OnStop() { m_bRunning = false; }
    
       virtual int OnRun() 
       {
             while (m_bRunning) {
                  do your job;
             }
       }                 
    };
    
    int main(int argc, char **argv)
    {
          ThreadLoop oLoop;
    
          IThread *pThread = ThrdCreate(&oLoop);
          // Start the thread, it will call Loop::OnStart() 
          //and then call Loop::OnRun() internally.
          pThread->Start();
          do your things here. when it is time to stop the thread, call stop().
          // Stop the thread, it will call Loop::OnStop(), 
          // so Loop::OnRun() will go to the end
          pThread->Stop();
          // done, destroy the thread
          pThread->Destroy();
    }
    
    class ThreadLoop : public MyThread
    {
    public:
       virtual bool OnStart() {  }  
    
       virtual bool OnStop() { }
    
       virtual int OnRun() 
       {
             do your job until finish.
       }                 
    };
    
    int main(int argc, char **argv)
    {
          ThreadLoop oLoop;
    
          IThread *pThread = ThrdCreate(&oLoop);
          // Start the thread, it will call Loop::OnStart() 
          //and then call Loop::OnRun() internally.
          pThread->Start();
          do your things here. Since you don't know when the job will 
          finish in the thread loop. call wait().
          // Wait the thread, it doesn't call Loop::OnStop()
          pThread->Wait();
          // done, destroy the thread
          pThread->Destroy();
    }
    
    http://effoaddon.googlecode.com/svn/trunk/devel/effo/codebase/addons/thrd/src/thrd/thrd.cpp