[Groonga-commit] groonga/grnxx at c5b2f4a [master] Implement grnxx::Thread.

Back to archive index

susumu.yata null+****@clear*****
Tue Apr 30 22:04:33 JST 2013


susumu.yata	2013-04-30 22:04:33 +0900 (Tue, 30 Apr 2013)

  New Revision: c5b2f4aeba3cb9d6218d9f1ee93c425179f8361b
  https://github.com/groonga/grnxx/commit/c5b2f4aeba3cb9d6218d9f1ee93c425179f8361b

  Message:
    Implement grnxx::Thread.

  Modified files:
    lib/grnxx/thread.cpp
    lib/grnxx/thread.hpp

  Modified: lib/grnxx/thread.cpp (+157 -0)
===================================================================
--- lib/grnxx/thread.cpp    2013-04-30 16:38:46 +0900 (5d02d79)
+++ lib/grnxx/thread.cpp    2013-04-30 22:04:33 +0900 (8df15dd)
@@ -18,7 +18,11 @@
 #include "grnxx/thread.hpp"
 
 #ifdef GRNXX_WINDOWS
+# include <errno.h>
+# include <process.h>
 # include <windows.h>
+#else  // GRNXX_WINDOWS
+# include <pthread.h>
 #endif  // GRNXX_WINDOWS
 
 #ifdef GRNXX_HAS_SCHED_YIELD
@@ -33,9 +37,162 @@
 //#include <chrono>
 //#include <thread>
 
+#include "grnxx/error.hpp"
+#include "grnxx/logger.hpp"
 #include "grnxx/time/system_clock.hpp"
 
 namespace grnxx {
+namespace {
+
+class ThreadImpl : public Thread {
+ public:
+  using Routine = Thread::Routine;
+
+  ThreadImpl();
+  ~ThreadImpl();
+
+  bool start(const Routine &routine);
+
+  bool join();
+  bool detach();
+
+ private:
+#ifdef GRNXX_WINDOWS
+  HANDLE thread_;
+#else  // GRNXX_WINDOWS
+  pthread_t thread_;
+#endif  // GRNXX_WINDOWS
+  bool joinable_;
+
+#ifdef GRNXX_WINDOWS
+  static unsigned thread_main(void *arg);
+#else  // GRNXX_WINDOWS
+  static void *thread_main(void *arg);
+#endif  // GRNXX_WINDOWS
+};
+
+ThreadImpl::ThreadImpl() : thread_(), joinable_(false) {}
+
+ThreadImpl::~ThreadImpl() {
+  // A thread must be join()ed or detach()ed.
+  if (joinable_) {
+    GRNXX_ERROR() << "running thread";
+  }
+}
+
+bool ThreadImpl::start(const Routine &routine) {
+  std::unique_ptr<Routine> routine_clone(new (std::nothrow) Routine(routine));
+  if (!routine_clone) {
+    GRNXX_ERROR() << "new std::function<void()> failed";
+    return false;
+  }
+#ifdef GRNXX_WINDOWS
+  const uintptr_t handle = ::_beginthreadex(nullptr, 0, thread_main,
+                                            routine_clone.get(), 0, nullptr);
+  if (handle == 0) {
+    GRNXX_ERROR() << "failed to create thread: '_beginthreadex' "
+                  << Error(errno);
+    return false;
+  }
+  thread_ = reinterpret_cast<HANDLE>(handle);
+#else  // GRNXX_WINDOWS
+  const int error = ::pthread_create(&thread_, nullptr, thread_main,
+                                     routine_clone.get());
+  if (error != 0) {
+    GRNXX_ERROR() << "failed to create thread: '::pthread_create' "
+                  << Error(error);
+    return false;
+  }
+#endif  // GRNXX_WINDOWS
+  routine_clone.release();
+  joinable_ = true;
+  return true;
+}
+
+bool ThreadImpl::join() {
+  if (!joinable_) {
+    GRNXX_ERROR() << "invalid operation: joinable = false";
+    return false;
+  }
+  bool result = true;
+#ifdef GRNXX_WINDOWS
+  if (::WaitForSingleObject(thread_, INFINITE) == WAIT_FAILED) {
+    GRNXX_ERROR() << "failed to join thread: '::WaitForSingleObject' "
+                  << Error(::GetLastError());
+    result = false;
+  }
+  if (::CloseHandle(thread_) != 0) {
+    GRNXX_ERROR() << "failed to close thread: '::CloseHandle' "
+                  << Error(::GetLastError());
+    result = false;
+  }
+#else  // GRNXX_WINDOWS
+  const int error = ::pthread_join(thread_, nullptr);
+  if (error != 0) {
+    GRNXX_ERROR() << "failed to join thread: '::pthread_join' "
+                  << Error(error);
+    result = false;
+  }
+#endif  // GRNXX_WINDOWS
+  joinable_ = false;
+  return result;
+}
+
+bool ThreadImpl::detach() {
+  if (!joinable_) {
+    GRNXX_ERROR() << "invalid operation: joinable = false";
+    return false;
+  }
+  bool result = true;
+#ifdef GRNXX_WINDOWS
+  if (::CloseHandle(thread_) != 0) {
+    GRNXX_ERROR() << "failed to detach thread: '::CloseHandle' "
+                  << Error(::GetLastError());
+    result = false;
+  }
+#else  // GRNXX_WINDOWS
+  const int error = ::pthread_detach(thread_);
+  if (error != 0) {
+    GRNXX_ERROR() << "failed to detach thread: '::pthread_detach' "
+                  << Error(error);
+    result = false;
+  }
+#endif  // GRNXX_WINDOWS
+  joinable_ = false;
+  return result;
+}
+
+#ifdef GRNXX_WINDOWS
+unsigned ThreadImpl::thread_main(void *arg) {
+  std::unique_ptr<Routine> routine(static_cast<Routine *>(arg));
+  (*routine)();
+  ::_endthreadex(0);
+  return 0;
+}
+#else  // GRNXX_WINDOWS
+void *ThreadImpl::thread_main(void *arg) {
+  std::unique_ptr<Routine> routine(static_cast<Routine *>(arg));
+  (*routine)();
+  return nullptr;
+}
+#endif  // GRNXX_WINDOWS
+
+}  // namespace
+
+Thread::Thread() {}
+Thread::~Thread() {}
+
+Thread *Thread::create(const Routine &routine) {
+  std::unique_ptr<ThreadImpl> thread(new (std::nothrow) ThreadImpl);
+  if (!thread) {
+    GRNXX_ERROR() << "new grnxx::ThreadImpl failed";
+    return nullptr;
+  }
+  if (!thread->start(routine)) {
+    return nullptr;
+  }
+  return thread.release();
+}
 
 void Thread::yield() {
 #ifdef GRNXX_WINDOWS

  Modified: lib/grnxx/thread.hpp (+17 -3)
===================================================================
--- lib/grnxx/thread.hpp    2013-04-30 16:38:46 +0900 (de7e851)
+++ lib/grnxx/thread.hpp    2013-04-30 22:04:33 +0900 (fd81cb8)
@@ -18,6 +18,8 @@
 #ifndef GRNXX_THREAD_HPP
 #define GRNXX_THREAD_HPP
 
+#include <functional>
+
 #include "grnxx/basic.hpp"
 #include "grnxx/time/time.hpp"
 
@@ -25,14 +27,26 @@ namespace grnxx {
 
 class Thread {
  public:
+  using Routine = std::function<void()>;
+
+  Thread();
+  virtual ~Thread();
+
+  // Create a thread.
+  static Thread *create(const std::function<void()> &routine);
+
+  // Yield the processor/core associated with the current thread.
   static void yield();
 
+  // Sleep for "duration".
   static void sleep_for(Duration duration);
+  // Sleep until "time".
   static void sleep_until(Time time);
 
- private:
-  Thread(const Thread &);
-  Thread &operator=(const Thread &);
+  // Wait until the thread finishes.
+  virtual bool join() = 0;
+  // Separate the thread from this object.
+  virtual bool detach() = 0;
 };
 
 }  // namespace grnxx
-------------- next part --------------
HTML����������������������������...
Download 



More information about the Groonga-commit mailing list
Back to archive index