Make the Thread state machine more strict
authorMikko Rasa <tdb@tdb.fi>
Mon, 22 Apr 2013 10:54:32 +0000 (13:54 +0300)
committerMikko Rasa <tdb@tdb.fi>
Mon, 22 Apr 2013 11:02:02 +0000 (14:02 +0300)
Trying to re-launch a thread after it has finished now throws a
logic_error.

Added a state to indicate the thread having finished.

source/core/thread.cpp
source/core/thread.h

index cfc0c37573d02a100df148a433a0bf365b76111f..6c542e6a6712d4e19323fbd779c401abd7ea4215 100644 (file)
@@ -4,8 +4,11 @@
 #include <pthread.h>
 #include <signal.h>
 #endif
+#include <stdexcept>
 #include "thread.h"
 
+using namespace std;
+
 namespace Msp {
 
 struct Thread::Private
@@ -19,33 +22,35 @@ struct Thread::Private
        Private(): handle(0) { }
 
 #ifdef WIN32
-       static DWORD WINAPI main_wrapper(void *t)
-       { reinterpret_cast<Thread *>(t)->main(); return 0; }
+       static DWORD WINAPI
 #else
-       static void *main_wrapper(void *t)
-       { reinterpret_cast<Thread *>(t)->main(); return 0; }
+       static void *
 #endif
+       main_wrapper(void *a)
+       {
+               Thread *t = reinterpret_cast<Thread *>(a);
+               t->main();
+               t->state_ = FINISHED;
+               return 0;
+       }
 };
 
 
 Thread::Thread():
        priv_(new Private),
-       launched_(false)
+       state_(PENDING)
 { }
 
 Thread::~Thread()
 {
-       if(launched_)
-       {
-               kill();
-               join();
-       }
+       kill();
+       join();
        delete priv_;
 }
 
 void Thread::join()
 {
-       if(!launched_)
+       if(state_>=JOINED)
                return;
 
 #ifdef WIN32
@@ -53,22 +58,26 @@ void Thread::join()
 #else
        pthread_join(priv_->handle, 0);
 #endif
-       launched_ = false;
+       state_ = JOINED;
 }
 
 void Thread::kill()
 {
+       if(state_!=RUNNING)
+               return;
+
 #ifdef WIN32
        TerminateThread(priv_->handle, 0);
 #else
        pthread_kill(priv_->handle, SIGKILL);
 #endif
+       state_ = KILLED;
 }
 
 void Thread::launch()
 {
-       if(launched_)
-               return;
+       if(state_>=RUNNING)
+               throw logic_error("already launched");
 
 #ifdef WIN32
        DWORD dummy;  // Win9x needs the lpTthreadId parameter
@@ -76,7 +85,7 @@ void Thread::launch()
 #else
        pthread_create(&priv_->handle, 0, &Private::main_wrapper, this);
 #endif
-       launched_ = true;
+       state_ = RUNNING;
 }
 
 } // namespace Msp
index ae257078569c47844e0d4502886f5de403371885..81494eaf5e47a007d6bd6207293a972920277362 100644 (file)
@@ -15,8 +15,17 @@ class Thread
 private:
        struct Private;
 
+       enum State
+       {
+               PENDING,
+               RUNNING,
+               FINISHED,
+               KILLED,
+               JOINED
+       };
+
        Private *priv_;
-       bool launched_;
+       State state_;
 
 protected:
        Thread();
@@ -26,6 +35,9 @@ private:
 public:
        virtual ~Thread();
 
+       /** Indicates whether the thread has finished running. */
+       bool is_finished() { return state_>=FINISHED; }
+
        /** Waits for the thread to exit.  Calling this from the thread will cause a
        deadlock. */
        void join();
@@ -33,8 +45,11 @@ public:
        /** Violently terminates the thread.  This should only be used as a last
        resort, as the thread gets no chance to clean up. */
        void kill();
+
 protected:
+       /** Starts the thread.  Can only be called once for each Thread instance. */
        void launch();
+
        virtual void main() = 0;
 };