A way to destroy the stream class

Here is the skeleton of my stream class:

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;                
};

Somewhere in the code I create an instance MyThread, and later I want to destroy it. In this case, called MyThread~MyThread(). MyThread:svc()still working and using object data elements. So I need a way to politely tell me to MyThread:svc()stop spinning before proceeding with the destructor.

What is an acceptable way to destroy a stream object?

Note. I am looking for an agnostic solution to the platform.

UPD: , , ++, . , : , ++, (, join(), ?

+3
8

, ( ):

, DTor . .


-, , . .

, , , , . , , , .


-, :
, . , , , , , .

, . . :

  • Thread Handle Object - , , , , . , Join, IsFinished, , .

( , threafFunc , , )

  1. - . , , : . - , - .

: start() svc()

API (XxxxPtr , , 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()
}

ThreadPtr, svc(). , . Thread::Start , .


: , ?
, - , . :

  • , . , .
  • . .
  • - , . ( ) , .
+7

API-, , "" . , .

,

  • (, false).
  • , , , .
  • ( , .).

" " " " (a-la Java Thread Runnable, , , Runnable ).

, , "shutdown" , , .

  • , .
  • , .
  • , , .

, ++ , , , .

+4

svc -

while (alive){ //loops}
//free resources after while.

false. pleaseDie(), false , Thread .

void
Thread::pleaseDie()
{

 this->alive = false;
}
+1

, , . , svc(). , , , ", ". bool ( ), svc() , . stop() , , svc(), "runnable", stop(), "stoppable".

, , , . , . stop(). , , "ok, I'm really stop now", , svc(). , "" , svc(). "" .

+1

.

: pthreads

pthread_kill(pthread_t thread, int sig);

. , . , undefined.

signall. , , . , , , , .

. , ( , undefined , ). , , , .

, , , , .

, , . , ( , ). SIGSEGV. , , , !

.
.

pthreads:

#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
>
+1

(, MyThreadMngr), , , .. - , , MyThreadMngr .. , .

, , .

0

, -

while(isRunning())
{
     ... thread implementation ...
}

, , , WIN32, TerminateThread .

0

I give a simple and clean design, no signal, no synchronization, no need for killing.

for your MyThread, I suggest renaming and adding as shown below:

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;                 
}; 

the user of the thread interface will control the lifetime of MyThread.

and actually the real flow object is as follows:

    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);

See full interface

http://effoaddon.googlecode.com/svn/trunk/devel/effo/codebase/addons/thrd/include/thrd_i.h

Coding Examples

Case 1. Controlled flow cycle

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();
}

Case 2. I do not know when the flow will stop

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();
}

Full implementation of IThread:

cm

http://effoaddon.googlecode.com/svn/trunk/devel/effo/codebase/addons/thrd/src/thrd/thrd.cpp
0
source

Source: https://habr.com/ru/post/1719432/


All Articles