diff --git a/src/client/tile.cpp b/src/client/tile.cpp
index f918dee2920267a176f8d2e36eb381cbb1600002..995526ea8c2a5f9c624ff3cabe81835280fa063c 100644
--- a/src/client/tile.cpp
+++ b/src/client/tile.cpp
@@ -439,7 +439,7 @@ TextureSource::TextureSource(IrrlichtDevice *device):
 {
 	assert(m_device); // Pre-condition
 
-	m_main_thread = get_current_thread_id();
+	m_main_thread = thr_get_current_thread_id();
 
 	// Add a NULL TextureInfo as the first index, named ""
 	m_textureinfo_cache.push_back(TextureInfo(""));
@@ -502,7 +502,7 @@ u32 TextureSource::getTextureId(const std::string &name)
 	/*
 		Get texture
 	*/
-	if (get_current_thread_id() == m_main_thread)
+	if (thr_is_current_thread(m_main_thread))
 	{
 		return generateTexture(name);
 	}
@@ -604,7 +604,7 @@ u32 TextureSource::generateTexture(const std::string &name)
 	/*
 		Calling only allowed from main thread
 	*/
-	if (get_current_thread_id() != m_main_thread) {
+	if (!thr_is_current_thread(m_main_thread)) {
 		errorstream<<"TextureSource::generateTexture() "
 				"called not from main thread"<<std::endl;
 		return 0;
@@ -704,7 +704,7 @@ void TextureSource::insertSourceImage(const std::string &name, video::IImage *im
 {
 	//infostream<<"TextureSource::insertSourceImage(): name="<<name<<std::endl;
 
-	sanity_check(get_current_thread_id() == m_main_thread);
+	sanity_check(thr_is_current_thread(m_main_thread));
 
 	m_sourcecache.insert(name, img, true, m_device->getVideoDriver());
 	m_source_image_existence.set(name, true);
@@ -2057,7 +2057,7 @@ video::ITexture *TextureSource::getShaderFlagsTexture(bool normalmap_present)
 {
 	std::string tname = "__shaderFlagsTexture";
 	tname += normalmap_present ? "1" : "0";
-	
+
 	if (isKnownSourceImage(tname)) {
 		return getTexture(tname);
 	} else {
diff --git a/src/debug.cpp b/src/debug.cpp
index 82aa6d5193024c542d0668cb134cfbb4dc4dc142..9f10426467309c7cede129ef3014f2501c63857d 100644
--- a/src/debug.cpp
+++ b/src/debug.cpp
@@ -45,7 +45,7 @@ void sanity_check_fn(const char *assertion, const char *file,
 		unsigned int line, const char *function)
 {
 	errorstream << std::endl << "In thread " << std::hex
-		<< (unsigned long)get_current_thread_id() << ":" << std::endl;
+		<< (unsigned long)thr_get_current_thread_id() << ":" << std::endl;
 	errorstream << file << ":" << line << ": " << function
 		<< ": An engine assumption '" << assertion << "' failed." << std::endl;
 
@@ -58,7 +58,7 @@ void fatal_error_fn(const char *msg, const char *file,
 		unsigned int line, const char *function)
 {
 	errorstream << std::endl << "In thread " << std::hex
-		<< (unsigned long)get_current_thread_id() << ":" << std::endl;
+		<< (unsigned long)thr_get_current_thread_id() << ":" << std::endl;
 	errorstream << file << ":" << line << ": " << function
 		<< ": A fatal error occured: " << msg << std::endl;
 
@@ -130,6 +130,13 @@ void DebugStack::print(std::ostream &os, bool everything)
 		os<<"Probably overflown."<<std::endl;
 }
 
+// Note:  Using pthread_t (that is, threadid_t on POSIX platforms) as the key to
+// a std::map is naughty.  Formally, a pthread_t may only be compared using
+// pthread_equal() - pthread_t lacks the well-ordered property needed for
+// comparisons in binary searches.  This should be fixed at some point by
+// defining a custom comparator with an arbitrary but stable ordering of
+// pthread_t, but it isn't too important since none of our supported platforms
+// implement pthread_t as a non-ordinal type.
 std::map<threadid_t, DebugStack*> g_debug_stacks;
 Mutex g_debug_stacks_mutex;
 
@@ -158,7 +165,7 @@ void debug_stacks_print()
 
 DebugStacker::DebugStacker(const char *text)
 {
-	threadid_t threadid = get_current_thread_id();
+	threadid_t threadid = thr_get_current_thread_id();
 
 	MutexAutoLock lock(g_debug_stacks_mutex);
 
diff --git a/src/itemdef.cpp b/src/itemdef.cpp
index 08ff887b2ff3c45798d36e751ce43d267009df54..2971d4e88a26b7cd9fd501e6c508291d2e4db7d3 100644
--- a/src/itemdef.cpp
+++ b/src/itemdef.cpp
@@ -241,7 +241,7 @@ class CItemDefManager: public IWritableItemDefManager
 	{
 
 #ifndef SERVER
-		m_main_thread = get_current_thread_id();
+		m_main_thread = thr_get_current_thread_id();
 #endif
 		clear();
 	}
@@ -317,7 +317,7 @@ class CItemDefManager: public IWritableItemDefManager
 				<<name<<"\""<<std::endl;
 
 		// This is not thread-safe
-		sanity_check(get_current_thread_id() == m_main_thread);
+		sanity_check(thr_is_current_thread(m_main_thread));
 
 		// Skip if already in cache
 		ClientCached *cc = NULL;
@@ -448,7 +448,7 @@ class CItemDefManager: public IWritableItemDefManager
 		if(cc)
 			return cc;
 
-		if(get_current_thread_id() == m_main_thread)
+		if(thr_is_current_thread(m_main_thread))
 		{
 			return createClientCachedDirect(name, gamedef);
 		}
diff --git a/src/log.cpp b/src/log.cpp
index 4f77101f932efde992e09d2c433ef6e8d9a3854f..e15bed52acb5bde99f2746a238d5b7143bf04bbc 100644
--- a/src/log.cpp
+++ b/src/log.cpp
@@ -184,14 +184,14 @@ void Logger::setLevelSilenced(LogLevel lev, bool silenced)
 
 void Logger::registerThread(const std::string &name)
 {
-	threadid_t id = get_current_thread_id();
+	threadid_t id = thr_get_current_thread_id();
 	MutexAutoLock lock(m_mutex);
 	m_thread_names[id] = name;
 }
 
 void Logger::deregisterThread()
 {
-	threadid_t id = get_current_thread_id();
+	threadid_t id = thr_get_current_thread_id();
 	MutexAutoLock lock(m_mutex);
 	m_thread_names.erase(id);
 }
@@ -215,7 +215,7 @@ const std::string Logger::getThreadName()
 {
 	std::map<threadid_t, std::string>::const_iterator it;
 
-	threadid_t id = get_current_thread_id();
+	threadid_t id = thr_get_current_thread_id();
 	it = m_thread_names.find(id);
 	if (it != m_thread_names.end())
 		return it->second;
diff --git a/src/shader.cpp b/src/shader.cpp
index cbde9295e587d4ad918cd2826e2350039605cc2d..917d878bb213b510f7564ab9de68092857f97ee8 100644
--- a/src/shader.cpp
+++ b/src/shader.cpp
@@ -367,7 +367,7 @@ ShaderSource::ShaderSource(IrrlichtDevice *device):
 
 	m_shader_callback = new ShaderCallback(this, "default");
 
-	m_main_thread = get_current_thread_id();
+	m_main_thread = thr_get_current_thread_id();
 
 	// Add a dummy ShaderInfo as the first index, named ""
 	m_shaderinfo_cache.push_back(ShaderInfo());
@@ -397,7 +397,7 @@ u32 ShaderSource::getShader(const std::string &name,
 		Get shader
 	*/
 
-	if(get_current_thread_id() == m_main_thread){
+	if (thr_is_current_thread(m_main_thread)) {
 		return getShaderIdDirect(name, material_type, drawtype);
 	} else {
 		/*errorstream<<"getShader(): Queued: name=\""<<name<<"\""<<std::endl;*/
@@ -456,7 +456,7 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name,
 	/*
 		Calling only allowed from main thread
 	*/
-	if(get_current_thread_id() != m_main_thread){
+	if (!thr_is_current_thread(m_main_thread)) {
 		errorstream<<"ShaderSource::getShaderIdDirect() "
 				"called not from main thread"<<std::endl;
 		return 0;
@@ -504,7 +504,7 @@ void ShaderSource::insertSourceShader(const std::string &name_of_shader,
 			"name_of_shader=\""<<name_of_shader<<"\", "
 			"filename=\""<<filename<<"\""<<std::endl;*/
 
-	sanity_check(get_current_thread_id() == m_main_thread);
+	sanity_check(thr_is_current_thread(m_main_thread));
 
 	m_sourcecache.insert(name_of_shader, filename, program, true);
 }
diff --git a/src/threads.h b/src/threads.h
index bc3bf571d2d8a44aafdadd2b6b6f3dfa6a86e5c7..176b69c2ee657c0680467df3fbd24e842be2ca3f 100644
--- a/src/threads.h
+++ b/src/threads.h
@@ -20,22 +20,75 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #ifndef THREADS_HEADER
 #define THREADS_HEADER
 
+//
+// Determine which threading API we will use
+//
+#if __cplusplus >= 201103L
+	#define USE_CPP11_THREADS 1
+#elif defined(_WIN32)
+	#define USE_WIN_THREADS 1
+#else
+	#define USE_POSIX_THREADS 1
+#endif
+
+///////////////
+
+
+#if USE_CPP11_THREADS
+	#include <thread>
+#endif
+
 #include "threading/mutex.h"
 
-#if defined(WIN32) || defined(_WIN32_WCE)
-typedef DWORD threadid_t;
-#else
-typedef pthread_t threadid_t;
+//
+// threadid_t, threadhandle_t
+//
+#if USE_CPP11_THREADS
+	typedef std::thread::id threadid_t;
+	typedef std::thread::native_handle_type threadhandle_t;
+#elif USE_WIN_THREADS
+	typedef DWORD threadid_t;
+	typedef HANDLE threadhandle_t;
+#elif USE_POSIX_THREADS
+	typedef pthread_t threadid_t;
+	typedef pthread_t threadhandle_t;
+#endif
+
+//
+// ThreadStartFunc
+//
+#if USE_CPP11_THREADS || USE_POSIX_THREADS
+	typedef void *(ThreadStartFunc)(void *param);
+#elif defined(_WIN32_WCE)
+	typedef DWORD (ThreadStartFunc)(LPVOID param);
+#elif defined(_WIN32)
+	typedef DWORD WINAPI (ThreadStartFunc)(LPVOID param);
 #endif
 
-inline threadid_t get_current_thread_id()
+
+inline threadid_t thr_get_current_thread_id()
 {
-#if defined(WIN32) || defined(_WIN32_WCE)
+#if USE_CPP11_THREADS
+	return std::this_thread::get_id();
+#elif USE_WIN_THREADS
 	return GetCurrentThreadId();
-#else
+#elif USE_POSIX_THREADS
 	return pthread_self();
 #endif
 }
 
+inline bool thr_compare_thread_id(threadid_t thr1, threadid_t thr2)
+{
+#if USE_POSIX_THREADS
+	return pthread_equal(thr1, thr2);
+#else
+	return thr1 == thr2;
 #endif
+}
 
+inline bool thr_is_current_thread(threadid_t thr)
+{
+	return thr_compare_thread_id(thr_get_current_thread_id(), thr);
+}
+
+#endif