Skip to content
Snippets Groups Projects
threader.h 2.11 KiB
Newer Older
  • Learn to ignore specific revisions
  • slevy's avatar
    slevy committed
    #ifndef THREADABLE_H
    #define THREADABLE_H 1
    
    /*
     * Generic class for something readable by a threaded assistant
     */
    
    #include <pthread.h>
    
    template <class T> class Threader {
    
      private:
        bool threaded_;		// is a separate reader thread running?
        pthread_t th_;
        pthread_mutex_t mut_;	// lock on shared data
        char *name_;
    
      public:
    
        Threader() : threaded_(false), name_(NULL)
        {
    	pthread_mutex_init( &mut_, NULL );
        }
    
        class Thunk {
    	void *(T::*func_)(void);
    	T *inst_;
    
    	// private constructor -- thanks to Matt Hall
    	Thunk( T *inst, void *(T::*func)() ) : inst_(inst), func_(func)
    	{ }
    
          public:
    	static Thunk *make( T *inst, void *(T::*func)(void) ) {
    	    return new Thunk( inst, func );
    	}
    
    	static void *call( Thunk *deleteme ) {
    	    Thunk t = *deleteme;
    	    delete deleteme;
    	    return ((t.inst_)->*(t.func_))();
    	}
        };
    
      public:
    
        void start( T *inst, void *(T::*func)(void) ) {
    
    	threaded_ = true;
    
    	Thunk *g = Thunk::make( inst, func );
    	pthread_create( &th_, NULL, (void *(*)(void *))&g->call, (void *)g );
        }
    
        pthread_mutex_t &mutex() { return mut_; }
    
        bool threading() const { return threaded_; }
    
        void lock() {
    	if(threaded_) {
    	    if(pthread_mutex_lock( &mut_ ) != 0) {
    		fprintf(stderr, "%s->lock(): %s\n",
    			name_ ? name_ : "Threader", strerror(errno));
    	    }
    	}
        }
    
        void unlock() {
    	if(threaded_) {
    	    if(pthread_mutex_unlock( &mut_ ) != 0) {
    		fprintf(stderr, "%s->unlock(): %s\n",
    			name_ ? name_ : "Threader", strerror(errno));
    	    }
    	}
        }
        void testcancel() {
    	if(threaded_) pthread_testcancel();
        }
    
        void cancel() {
    	if(threaded_) {
    	    if(pthread_cancel( th_ ) != 0) {
    		fprintf(stderr, "%s->cancel(0x%lx): %s\n",
    			name_ ? name_ : "Threadable",
    			(long int)th_, strerror(errno));
    	    }
    	}
        }
    
    };
    
    // Maybe convenient for above?
    //  { scoped_lock lock(threader.mutex());
    //    mess with threader's contents
    //  }
    
    class scoped_lock {
        pthread_mutex_t *m_;
    
      public:
        scoped_lock( pthread_mutex_t &mut ) {
    	m_ = &mut;
    	pthread_mutex_lock( m_ );
        }
    
        ~scoped_lock() {
    	pthread_mutex_unlock( m_ );
        }
    };
    
    #endif /*THREADABLE_H*/