Commits

Christian Fischer  committed 411ba23

added thread class

  • Participants
  • Parent commits 04c4409

Comments (0)

Files changed (6)

File libraries/android-native/wiesel-base/Android.mk

 # configure the module
 LOCAL_MODULE               := wiesel-base
 LOCAL_MODULE_FILENAME      := libwieselbase
-LOCAL_CFLAGS               := -Werror
+LOCAL_CFLAGS               :=
 LOCAL_LDLIBS               := 
-LOCAL_STATIC_LIBRARIES     := 
+LOCAL_STATIC_LIBRARIES     := pthread
 LOCAL_SRC_FILES            := $(MY_FILES)
 LOCAL_C_INCLUDES           := $(MY_LOCAL_FOLDERS)
 LOCAL_EXPORT_C_INCLUDES    := $(MY_LOCAL_FOLDERS)

File libraries/android-native/wiesel-base/src/wiesel/wiesel-base-config.h

+/**
+ * Copyright (C) 2012
+ * Christian Fischer
+ *
+ * https://bitbucket.org/baldur/wiesel/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+#ifndef __WIESEL_BASE_CONFIG_H__
+#define __WIESEL_BASE_CONFIG_H__
+
+// determine which threadapi to use
+#define WIESEL_THREADAPI_PTHREAD	1
+#define WIESEL_THREADAPI_WIN32		0
+
+#endif // __WIESEL_BASE_CONFIG_H__

File libraries/desktop/wiesel-base/module.cmake

 
 # export include directories of this library for other targets
 wiesel_module_export_includes(wiesel-base ${WIESEL_SRC_DIR}/base)
+
+# import thread API
+set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
+include(FindThreads)
+
+set(WIESEL_THREADAPI_PTHREAD		${CMAKE_USE_PTHREADS_INIT})
+set(WIESEL_THREADAPI_WIN32			${CMAKE_USE_WIN32_THREADS_INIT})
+
+target_link_libraries(wiesel-base ${CMAKE_THREAD_LIBS_INIT})
+
+# check if at least one threadapi was found
+if (
+		NOT "${WIESEL_THREADAPI_PTHREAD}"
+	AND	NOT "${WIESEL_THREADAPI_WIN32}"
+)
+	message(FATAL_ERROR "No supported threadapi found")
+endif()
+
+
+# finally, create the config file
+configure_file(
+		${WIESEL_SRC_DIR}/base/wiesel/wiesel-base-config.in
+		${WIESEL_GENERATED_DIR}/wiesel/wiesel-base-config.h
+)

File src/base/wiesel/util/thread.cpp

+/**
+ * Copyright (C) 2012
+ * Christian Fischer
+ *
+ * https://bitbucket.org/baldur/wiesel/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+#include "thread.h"
+
+using namespace wiesel;
+
+
+IRunnable::IRunnable() {
+	return;
+}
+
+IRunnable::~IRunnable() {
+	return;
+}
+
+
+
+
+#if WIESEL_THREADAPI_PTHREAD
+	static void* pthread_entry(void* arg) {
+		Thread *thread = reinterpret_cast<Thread*>(arg);
+		_thread_impl(thread);
+
+		return NULL;
+	}
+#endif // WIESEL_THREADAPI_PTHREAD
+
+
+#if WIESEL_THREADAPI_WIN32
+	static DWORD WINAPI win32_thread_entry(void* arg) {
+		Thread *thread = reinterpret_cast<Thread*>(arg);
+		_thread_impl(thread);
+
+		return 1;
+	}
+#endif // WIESEL_THREADAPI_WIN32
+
+
+
+
+Thread::Thread() {
+	this->runnable	= NULL;
+	init();
+}
+
+Thread::Thread(IRunnable* runnable) {
+	this->runnable	= keep(runnable);
+	init();
+}
+
+Thread::~Thread() {
+	assert(this->state == None);
+
+	#if WIESEL_THREADAPI_PTHREAD
+		if (thread_mutex != NULL) {
+			pthread_mutex_destroy(thread_mutex);
+			thread_mutex  = NULL;
+		}
+	#elif WIESEL_THREADAPI_WIN32
+		if (critical_section != NULL) {
+			DeleteCriticalSection(critical_section);
+			delete critical_section;
+			critical_section = NULL;
+		}
+	#endif
+
+	safe_release(runnable);
+
+	return;
+}
+
+
+void Thread::init() {
+	this->state		= None;
+
+	#if WIESEL_THREADAPI_PTHREAD
+		this->thread_mutex		= new pthread_mutex_t();
+		*(this->thread_mutex)	= PTHREAD_MUTEX_INITIALIZER;
+		pthread_mutex_init(thread_mutex, NULL);
+	#elif WIESEL_THREADAPI_WIN32
+		this->thread_handle		= 0;
+		this->critical_section	= new CRITICAL_SECTION();
+		InitializeCriticalSection(critical_section);
+	#endif
+
+	return;
+}
+
+
+bool Thread::start() {
+	assert(state == None);
+	
+	if (state == None) {
+		state  = Running;
+
+		// the running thread keeps a reference to itself
+		keep(this);
+
+		#if WIESEL_THREADAPI_PTHREAD
+			pthread_create(&thread_handle, NULL, &pthread_entry, reinterpret_cast<void*>(this));
+		#elif WIESEL_THREADAPI_WIN32
+			thread_handle = CreateThread(NULL, 0, &win32_thread_entry, reinterpret_cast<void*>(this), 0, NULL);
+			if (thread_handle == NULL) {
+				return false;
+			}
+		#else
+			#error no valid thread-API configured.
+		#endif
+
+		return true;
+	}
+
+	return false;
+}
+
+
+void Thread::detach() {
+	assert(state == Running || state == WaitingForJoin);
+
+	if (state == Running || state == WaitingForJoin) {
+		lock();
+
+		#if WIESEL_THREADAPI_PTHREAD
+			pthread_detach(thread_handle);
+		#elif WIESEL_THREADAPI_WIN32
+			CloseHandle(thread_handle);
+			thread_handle = NULL;
+		#else
+			#error no valid thread-API configured.
+		#endif
+
+		switch(state) {
+			case Running: {
+				state = RunningDetached;
+				break;
+			}
+
+			case WaitingForJoin: {
+				state = None;
+				break;
+			}
+
+			default: {
+				break;
+			}
+		}
+
+		unlock();
+	}
+
+	return;
+}
+
+
+void Thread::join() {
+	assert(state == Running || state == WaitingForJoin);
+
+	if (state == Running || state == WaitingForJoin) {
+		#if WIESEL_THREADAPI_PTHREAD
+			pthread_join(thread_handle, NULL);
+		#elif WIESEL_THREADAPI_WIN32
+			WaitForSingleObject(thread_handle, INFINITE);
+			CloseHandle(thread_handle);
+			thread_handle = NULL;
+		#else
+			#error no valid thread-API configured.
+		#endif
+
+		state = None;
+
+		// release the reference to the running thread
+		release(this);
+	}
+
+	return;
+}
+
+
+bool Thread::isRunning() const {
+	switch(state) {
+		case Running:
+		case RunningDetached:
+			return true;
+
+		default:
+			break;
+	}
+
+	return false;
+}
+
+
+void Thread::lock() {
+	#if WIESEL_THREADAPI_PTHREAD
+		pthread_mutex_lock(thread_mutex);
+	#else
+		EnterCriticalSection(critical_section);
+	#endif
+
+	// locking a thread increments the reference counter
+	keep(this);
+
+	return;
+}
+
+
+void Thread::unlock() {
+	assert(getReferenceCount() >= 1);
+
+	// releasing this lock will destroy our object,
+	// so we need to keep the mutex handle first
+	bool object_will_be_deleted = false;
+	if (getReferenceCount() <= 1) {
+		object_will_be_deleted = true;
+	}
+
+	#if WIESEL_THREADAPI_PTHREAD
+		pthread_mutex_t *mutex = this->thread_mutex;
+
+		if (object_will_be_deleted) {
+			this->thread_mutex = NULL;
+		}
+	#elif WIESEL_THREADAPI_WIN32
+		LPCRITICAL_SECTION cs = this->critical_section;
+
+		if (object_will_be_deleted) {
+			this->critical_section = NULL;
+		}
+	#endif
+
+	// clear the reference obtained by this lock
+	release(this);
+
+	#if WIESEL_THREADAPI_PTHREAD
+		pthread_mutex_unlock(mutex);
+
+		if (object_will_be_deleted) {
+			pthread_mutex_destroy(mutex);
+			delete mutex;
+		}
+	#elif WIESEL_THREADAPI_WIN32
+		LeaveCriticalSection(cs);
+
+		if (object_will_be_deleted) {
+			LeaveCriticalSection(cs);
+			delete cs;
+		}
+	#else
+		#error no valid thread-API configured.
+	#endif
+
+	return;
+}
+
+
+
+void Thread::run() {
+	if (runnable) {
+		runnable->run();
+	}
+
+	return;
+}
+
+
+
+void wiesel::_thread_impl(Thread *thread) {
+	assert(thread->state == Thread::Running || thread->state == Thread::RunningDetached);
+
+	thread->run();
+
+	{
+		thread->lock();
+
+		switch(thread->state) {
+			case Thread::Running: {
+				thread->state = Thread::WaitingForJoin;
+				break;
+			}
+
+			case Thread::RunningDetached: {
+				thread->state = Thread::None;
+				release(thread);
+				break;
+			}
+
+			default: {
+				break;
+			}
+		}
+
+		thread->unlock();
+	}
+
+	return;
+}

File src/base/wiesel/util/thread.h

+/**
+ * Copyright (C) 2012
+ * Christian Fischer
+ *
+ * https://bitbucket.org/baldur/wiesel/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+#ifndef __WIESEL_UTIL_THREAD_H__
+#define	__WIESEL_UTIL_THREAD_H__
+
+#include "shared_object.h"
+
+#include "wiesel/wiesel-base-config.h"
+
+#if WIESEL_THREADAPI_PTHREAD
+#	include <pthread.h>
+#endif
+
+#if WIESEL_THREADAPI_WIN32
+#	include <windows.h>
+#	include <process.h>
+#endif
+
+namespace wiesel {
+
+	class Thread;
+	void _thread_impl(Thread *thread);
+
+
+	/**
+	 * @brief A interface class for any object which should perform a single task.
+	 */
+	class WIESEL_BASE_EXPORT IRunnable : public virtual SharedObject
+	{
+	public:
+		IRunnable();
+		virtual ~IRunnable();
+
+	public:
+		/**
+		 * @brief Performs the task of this object.
+		 */
+		virtual void run() = 0;
+	};
+
+
+	/**
+	 * @brief A class managing a single threaded process.
+	 */
+	class WIESEL_BASE_EXPORT Thread : public IRunnable
+	{
+	friend void _thread_impl(Thread *thread);
+
+	protected:
+		Thread();
+
+	public:
+		/**
+		 * @brief Creates a new thread with a reference to a single \ref IRunnable object.
+		 * The task of this object will be executed in a seperate thread.
+		 */
+		Thread(IRunnable *runnable);
+
+		virtual ~Thread();
+
+	private:
+		void init();
+
+	public:
+		/**
+		 * @brief Starts this thread.
+		 * After starting, the caller should call either
+		 * \ref join() or \ref detach()
+		 * @return \c true on success.
+		 */
+		bool start();
+
+		/**
+		 * @brief Detaches this thread.
+		 */
+		void detach();
+
+		/**
+		 * @brief Wait for this thread until it has been finished.
+		 */
+		void join();
+
+		/**
+		 * @brief Check if this thread is still running.
+		 */
+		bool isRunning() const;
+
+	// locking
+	public:
+		void lock();
+		void unlock();
+
+	// IRunnable
+	public:
+		/**
+		 * @brief This function will be called, when the thread was started.
+		 * To be implemented by subclasses.
+		 */
+		virtual void run();
+
+	private:
+		enum State {
+			None,
+			Running,
+			RunningDetached,
+			WaitingForJoin,
+		};
+
+		IRunnable*		runnable;
+		State			state;
+
+	// api specific
+	private:
+		#if WIESEL_THREADAPI_PTHREAD
+			pthread_t			thread_handle;
+			pthread_mutex_t*	thread_mutex;
+		#elif WIESEL_THREADAPI_WIN32
+			HANDLE				thread_handle;
+			LPCRITICAL_SECTION	critical_section;
+		#endif
+	};
+}
+
+#endif	// __WIESEL_UTIL_THREAD_H__

File src/base/wiesel/wiesel-base-config.in

+/**
+ * Copyright (C) 2012
+ * Christian Fischer
+ *
+ * https://bitbucket.org/baldur/wiesel/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+#ifndef __WIESEL_BASE_CONFIG_H__
+#define __WIESEL_BASE_CONFIG_H__
+
+// determine which threadapi to use
+#cmakedefine01 WIESEL_THREADAPI_PTHREAD
+#cmakedefine01 WIESEL_THREADAPI_WIN32
+
+#endif // __WIESEL_BASE_CONFIG_H__