Windows上无法使用thread头文件

Windows上无法使用thread头文件

问题描述与分析

最近在学习C++多线程编程,没想到第一步就出现了问题。首先写了一份简单的测试代码(位于d:\test.cpp):

#include <iostream>
#include <mutex>
#include <thread>
using namespace std;
void f() { cout << "啊啊" << endl; }
int main() {
  thread a(f);

  a.join();

  system("pause");
  return 0;
}

命令行输入下述命令进行编译:

E:\SoftwareFiles\MinGW\bin\g++.exe -g -std=c++14 d:\test.cpp -o d:\test.exe

出现报错:

d:\test.cpp: In function 'int main()':
d:\test.cpp:7:3: error: 'thread' was not declared in this scope
    7 |   thread a(f);
      |   ^~~~~~
d:\test.cpp:4:1: note: 'std::thread' is defined in header '<thread>'; did you forget to '#include <thread>'?
    3 | #include <thread>
  +++ |+#include <thread>
    4 | using namespace std;
d:\test.cpp:9:3: error: 'a' was not declared in this scope
    9 |   a.join();
      |   ^

根据报错信息,g++似乎没有识别出我在文件内包含的thread头文件,但是我确实包含了呀,这是为什么呢?

Visual Studio Code中用Ctrl+左键点击头文件可以打开对应的头文件源代码,打开后发现其中的class thread{...};部分是暗色的,即有一些宏定义使得这段代码失效了(文章末尾会贴上我的电脑中完整的thread头文件源代码,供大家比对)。进一步查看是有个_GLIBCXX_HAS_GTHREADS宏没有定义:

......

#if defined(_GLIBCXX_HAS_GTHREADS) // ←这个if defined包的代码都是暗色(不可用)的

namespace std _GLIBCXX_VISIBILITY(default)
{
  ......

  class thread
  {
    ......
  }

_GLIBCXX_END_NAMESPACE_VERSION
} // namespace

#endif // _GLIBCXX_HAS_GTHREADS

......

也就是说class thread因为没有这个宏定义而被忽略掉了,编译器就会认为我没有包thread头文件,就会报错(还贴心地让我包头文件)。

尝试解决问题

既然是没有读到class thread的定义,那思路当然就是想办法让它读到了。我水平有限,不敢直接改头文件,所以尝试在代码中加上这个宏的定义。将d:\test.cpp代码改为:

#include <iostream>
#include <mutex>

#define _GLIBCXX_HAS_GTHREADS

#include <thread>
using namespace std;
void f() { cout << "啊啊" << endl; }
int main() {
  thread a(f);

  a.join();

  system("pause");
  return 0;
}

也就是手动加上这个宏定义,然后命令行编译:

E:\SoftwareFiles\MinGW\bin\g++.exe -g -std=c++14 d:\test.cpp -o d:\test.exe

结果报错更多了:

In file included from d:\test.cpp:6:
e:\softwarefiles\mingw\lib\gcc\mingw32\9.2.0\include\c++\thread:74:13: error: '__gthread_t' does not name a type; did you mean '__gthread_once'?
   74 |     typedef __gthread_t   native_handle_type;
      |             ^~~~~~~~~~~
      |             __gthread_once
e:\softwarefiles\mingw\lib\gcc\mingw32\9.2.0\include\c++\thread:79:7: error: 'native_handle_type' does not name a type
   79 |       native_handle_type _M_thread;
      |       ^~~~~~~~~~~~~~~~~~
e:\softwarefiles\mingw\lib\gcc\mingw32\9.2.0\include\c++\thread:85:28: error: expected ')' before '__id'
   85 |       id(native_handle_type __id) : _M_thread(__id) { }
      |         ~                  ^~~~~
      |                            )
e:\softwarefiles\mingw\lib\gcc\mingw32\9.2.0\include\c++\thread:177:5: error: 'native_handle_type' does not name a type
  177 |     native_handle_type
      |     ^~~~~~~~~~~~~~~~~~
e:\softwarefiles\mingw\lib\gcc\mingw32\9.2.0\include\c++\thread: In constructor 'std::thread::id::id()':
e:\softwarefiles\mingw\lib\gcc\mingw32\9.2.0\include\c++\thread:82:23: error: class 'std::thread::id' does not have any field named '_M_thread'
   82 |       id() noexcept : _M_thread() { }
      |                       ^~~~~~~~~
e:\softwarefiles\mingw\lib\gcc\mingw32\9.2.0\include\c++\thread: In function 'bool std::operator==(std::thread::id, std::thread::id)':
e:\softwarefiles\mingw\lib\gcc\mingw32\9.2.0\include\c++\thread:282:16: error: 'class std::thread::id' has no member named '_M_thread'
  282 |     return __x._M_thread == __y._M_thread;
      |                ^~~~~~~~~
e:\softwarefiles\mingw\lib\gcc\mingw32\9.2.0\include\c++\thread:282:33: error: 'class std::thread::id' has no member named '_M_thread'
  282 |     return __x._M_thread == __y._M_thread;
      |                                 ^~~~~~~~~
e:\softwarefiles\mingw\lib\gcc\mingw32\9.2.0\include\c++\thread: In function 'bool std::operator<(std::thread::id, std::thread::id)':
e:\softwarefiles\mingw\lib\gcc\mingw32\9.2.0\include\c++\thread:294:16: error: 'class std::thread::id' has no member named '_M_thread'
  294 |     return __x._M_thread < __y._M_thread;
      |                ^~~~~~~~~
e:\softwarefiles\mingw\lib\gcc\mingw32\9.2.0\include\c++\thread:294:32: error: 'class std::thread::id' has no member named '_M_thread'
  294 |     return __x._M_thread < __y._M_thread;
      |                                ^~~~~~~~~
e:\softwarefiles\mingw\lib\gcc\mingw32\9.2.0\include\c++\thread: In member function 'std::size_t std::hash<std::thread::id>::operator()(const std::thread::id&) const':
e:\softwarefiles\mingw\lib\gcc\mingw32\9.2.0\include\c++\thread:317:43: error: 'const class std::thread::id' has no member named '_M_thread'
  317 |       { return std::_Hash_impl::hash(__id._M_thread); }
      |                                           ^~~~~~~~~
e:\softwarefiles\mingw\lib\gcc\mingw32\9.2.0\include\c++\thread: In function 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, std::thread::id)':
e:\softwarefiles\mingw\lib\gcc\mingw32\9.2.0\include\c++\thread:327:23: error: 'class std::thread::id' has no member named '_M_thread'
  327 |  return __out << __id._M_thread;
      |                       ^~~~~~~~~
e:\softwarefiles\mingw\lib\gcc\mingw32\9.2.0\include\c++\thread: In function 'std::thread::id std::this_thread::get_id(
':
e:\softwarefiles\mingw\lib\gcc\mingw32\9.2.0\include\c++\thread:348:25: error: '__gthread_self' was not declared in this scope; did you mean '__gthread_once'?
  348 |       return thread::id(__gthread_self());
      |                         ^~~~~~~~~~~~~~
      |                         __gthread_once

看起来问题是有些具体的实现没搞定,或者被另外的宏屏蔽了。有点无从下手了,似乎这个不是自己开启宏定义就能解决这么简单。后来在网上搜索了很久了,大概搞清楚了怎么回事了,特此记录一下:

gccwindows上对多线程的支持有两套api,分别是win32posix,前者会禁用std::thread,对应的你可以使用_beginthreadex等函数创建线程(这个函数在头文件process.h中,一份典型的样例代码可见https://www.xuebuyuan.com/3255482.html,亲测可通过编译并正确输出结果);后者则支持std::thread。如果想查看自己的gcc采用了哪一套,可以在命令行输入命令:

g++ -v

我的输出是:

Using built-in specs.
COLLECT_GCC=E:\SoftwareFiles\MinGW\bin\g++.exe
COLLECT_LTO_WRAPPER=e:/softwarefiles/mingw/bin/../libexec/gcc/mingw32/9.2.0/lto-wrapper.exe
Target: mingw32
Configured with: ../src/gcc-9.2.0/configure --build=x86_64-pc-linux-gnu --host=mingw32 --target=mingw32 --disable-win32-registry --with-arch=i586 --with-tune=generic --enable-static --enable-shared --enable-threads --enable-languages=c,c++,objc,obj-c++,fortran,ada --with-dwarf2 --disable-sjlj-exceptions --enable-version-specific-runtime-libs --enable-libgomp --disable-libvtv --with-libiconv-prefix=/mingw --with-libintl-prefix=/mingw --enable-libstdcxx-debug --disable-build-format-warnings --prefix=/mingw --with-gmp=/mingw --with-mpfr=/mingw --with-mpc=/mingw --with-isl=/mingw --enable-nls --with-pkgversion='MinGW.org GCC Build-2'
Thread model: win32
gcc version 9.2.0 (MinGW.org GCC Build-2)

其中Thread model: win32就表明我的gcc采用了win32的线程api

解决问题

既然搞懂了原因,那就很好解决了,只要再装一个采用posixgcc,然后用它编译即可。

前往MinGW_W64的下载网站http://mingw-w64.org/doku.php/download/mingw-builds,点击页面上的Installation: Sourceforge中那个链接,就会自动跳转并开始下载安装包,例如我就会下载到mingw-w64-install.exe。双击运行,可以看到有选择线程架构的页面:

MinGW_W64安装页面

选好posix,然后安装好。在命令行中使用新的g++对一开始的d:test.cpp(即未加宏定义的)进行编译:

E:\SoftwareFiles\MinGW_W64\mingw32\bin\g++.exe -g -std=c++14 d:\test.cpp -o d:\test.exe

正常通过,然后命令行打开编译出来的可执行文件:

d:\test.exe

正常输出结果:

啊啊
Press any key to continue . . .

至此问题就完全解决了。

附录

  1. 原来的thread头文件源代码:

    // <thread> -*- C++ -*-
    
    // Copyright (C) 2008-2019 Free Software Foundation, Inc.
    //
    // This file is part of the GNU ISO C++ Library.  This library is free
    // software; you can redistribute it and/or modify it under the
    // terms of the GNU General Public License as published by the
    // Free Software Foundation; either version 3, 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 General Public License for more details.
    
    // Under Section 7 of GPL version 3, you are granted additional
    // permissions described in the GCC Runtime Library Exception, version
    // 3.1, as published by the Free Software Foundation.
    
    // You should have received a copy of the GNU General Public License and
    // a copy of the GCC Runtime Library Exception along with this program;
    // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
    // <http://www.gnu.org/licenses/>.
    
    /** @file include/thread
     *  This is a Standard C++ Library header.
     */
    
    #ifndef _GLIBCXX_THREAD
    #define _GLIBCXX_THREAD 1
    
    #pragma GCC system_header
    
    #if __cplusplus < 201103L
    # include <bits/c++0x_warning.h>
    #else
    
    #include <chrono>
    #include <memory>
    #include <tuple>
    #include <cerrno>
    #include <bits/functexcept.h>
    #include <bits/functional_hash.h>
    #include <bits/invoke.h>
    #include <bits/gthr.h>
    
    #if defined(_GLIBCXX_HAS_GTHREADS)
    
    namespace std _GLIBCXX_VISIBILITY(default)
    {
    _GLIBCXX_BEGIN_NAMESPACE_VERSION
    
      /**
       * @defgroup threads Threads
       * @ingroup concurrency
       *
       * Classes for thread support.
       * @{
       */
    
      /// thread
      class thread
      {
      public:
        // Abstract base class for types that wrap arbitrary functors to be
        // invoked in the new thread of execution.
        struct _State
        {
          virtual ~_State();
          virtual void _M_run() = 0;
        };
        using _State_ptr = unique_ptr<_State>;
    
        typedef __gthread_t			native_handle_type;
    
        /// thread::id
        class id
        {
          native_handle_type	_M_thread;
    
        public:
          id() noexcept : _M_thread() { }
    
          explicit
          id(native_handle_type __id) : _M_thread(__id) { }
    
        private:
          friend class thread;
          friend class hash<thread::id>;
    
          friend bool
          operator==(thread::id __x, thread::id __y) noexcept;
    
          friend bool
          operator<(thread::id __x, thread::id __y) noexcept;
    
          template<class _CharT, class _Traits>
    	friend basic_ostream<_CharT, _Traits>&
    	operator<<(basic_ostream<_CharT, _Traits>& __out, thread::id __id);
        };
    
      private:
        id				_M_id;
    
        // _GLIBCXX_RESOLVE_LIB_DEFECTS
        // 2097.  packaged_task constructors should be constrained
        // 3039. Unnecessary decay in thread and packaged_task
        template<typename _Tp>
          using __not_same = __not_<is_same<__remove_cvref_t<_Tp>, thread>>;
    
      public:
        thread() noexcept = default;
    
        template<typename _Callable, typename... _Args,
    	     typename = _Require<__not_same<_Callable>>>
          explicit
          thread(_Callable&& __f, _Args&&... __args)
          {
    	static_assert( __is_invocable<typename decay<_Callable>::type,
    				      typename decay<_Args>::type...>::value,
    	  "std::thread arguments must be invocable after conversion to rvalues"
    	  );
    
    #ifdef GTHR_ACTIVE_PROXY
    	// Create a reference to pthread_create, not just the gthr weak symbol.
    	auto __depend = reinterpret_cast<void(*)()>(&pthread_create);
    #else
    	auto __depend = nullptr;
    #endif
            _M_start_thread(_S_make_state(
    	      __make_invoker(std::forward<_Callable>(__f),
    			     std::forward<_Args>(__args)...)),
    	    __depend);
          }
    
        ~thread()
        {
          if (joinable())
    	std::terminate();
        }
    
        thread(const thread&) = delete;
    
        thread(thread&& __t) noexcept
        { swap(__t); }
    
        thread& operator=(const thread&) = delete;
    
        thread& operator=(thread&& __t) noexcept
        {
          if (joinable())
    	std::terminate();
          swap(__t);
          return *this;
        }
    
        void
        swap(thread& __t) noexcept
        { std::swap(_M_id, __t._M_id); }
    
        bool
        joinable() const noexcept
        { return !(_M_id == id()); }
    
        void
        join();
    
        void
        detach();
    
        thread::id
        get_id() const noexcept
        { return _M_id; }
    
        /** @pre thread is joinable
         */
        native_handle_type
        native_handle()
        { return _M_id._M_thread; }
    
        // Returns a value that hints at the number of hardware thread contexts.
        static unsigned int
        hardware_concurrency() noexcept;
    
      private:
        template<typename _Callable>
          struct _State_impl : public _State
          {
    	_Callable		_M_func;
    
    	_State_impl(_Callable&& __f) : _M_func(std::forward<_Callable>(__f))
    	{ }
    
    	void
    	_M_run() { _M_func(); }
          };
    
        void
        _M_start_thread(_State_ptr, void (*)());
    
        template<typename _Callable>
          static _State_ptr
          _S_make_state(_Callable&& __f)
          {
    	using _Impl = _State_impl<_Callable>;
    	return _State_ptr{new _Impl{std::forward<_Callable>(__f)}};
          }
    #if _GLIBCXX_THREAD_ABI_COMPAT
      public:
        struct _Impl_base;
        typedef shared_ptr<_Impl_base>	__shared_base_type;
        struct _Impl_base
        {
          __shared_base_type	_M_this_ptr;
          virtual ~_Impl_base() = default;
          virtual void _M_run() = 0;
        };
    
      private:
        void
        _M_start_thread(__shared_base_type, void (*)());
    
        void
        _M_start_thread(__shared_base_type);
    #endif
    
      private:
        // A call wrapper that does INVOKE(forwarded tuple elements...)
        template<typename _Tuple>
          struct _Invoker
          {
    	_Tuple _M_t;
    
    	template<typename>
    	  struct __result;
    	template<typename _Fn, typename... _Args>
    	  struct __result<tuple<_Fn, _Args...>>
    	  : __invoke_result<_Fn, _Args...>
    	  { };
    
    	template<size_t... _Ind>
    	  typename __result<_Tuple>::type
    	  _M_invoke(_Index_tuple<_Ind...>)
    	  { return std::__invoke(std::get<_Ind>(std::move(_M_t))...); }
    
    	typename __result<_Tuple>::type
    	operator()()
    	{
    	  using _Indices
    	    = typename _Build_index_tuple<tuple_size<_Tuple>::value>::__type;
    	  return _M_invoke(_Indices());
    	}
          };
    
        template<typename... _Tp>
          using __decayed_tuple = tuple<typename decay<_Tp>::type...>;
    
      public:
        // Returns a call wrapper that stores
        // tuple{DECAY_COPY(__callable), DECAY_COPY(__args)...}.
        template<typename _Callable, typename... _Args>
          static _Invoker<__decayed_tuple<_Callable, _Args...>>
          __make_invoker(_Callable&& __callable, _Args&&... __args)
          {
    	return { __decayed_tuple<_Callable, _Args...>{
    	    std::forward<_Callable>(__callable), std::forward<_Args>(__args)...
    	} };
          }
      };
    
      inline void
      swap(thread& __x, thread& __y) noexcept
      { __x.swap(__y); }
    
      inline bool
      operator==(thread::id __x, thread::id __y) noexcept
      {
        // pthread_equal is undefined if either thread ID is not valid, so we
        // can't safely use __gthread_equal on default-constructed values (nor
        // the non-zero value returned by this_thread::get_id() for
        // single-threaded programs using GNU libc). Assume EqualityComparable.
        return __x._M_thread == __y._M_thread;
      }
    
      inline bool
      operator!=(thread::id __x, thread::id __y) noexcept
      { return !(__x == __y); }
    
      inline bool
      operator<(thread::id __x, thread::id __y) noexcept
      {
        // Pthreads doesn't define any way to do this, so we just have to
        // assume native_handle_type is LessThanComparable.
        return __x._M_thread < __y._M_thread;
      }
    
      inline bool
      operator<=(thread::id __x, thread::id __y) noexcept
      { return !(__y < __x); }
    
      inline bool
      operator>(thread::id __x, thread::id __y) noexcept
      { return __y < __x; }
    
      inline bool
      operator>=(thread::id __x, thread::id __y) noexcept
      { return !(__x < __y); }
    
      // DR 889.
      /// std::hash specialization for thread::id.
      template<>
        struct hash<thread::id>
        : public __hash_base<size_t, thread::id>
        {
          size_t
          operator()(const thread::id& __id) const noexcept
          { return std::_Hash_impl::hash(__id._M_thread); }
        };
    
      template<class _CharT, class _Traits>
        inline basic_ostream<_CharT, _Traits>&
        operator<<(basic_ostream<_CharT, _Traits>& __out, thread::id __id)
        {
          if (__id == thread::id())
    	return __out << "thread::id of a non-executing thread";
          else
    	return __out << __id._M_thread;
        }
    
      /** @namespace std::this_thread
       *  @brief ISO C++ 2011 entities sub-namespace for thread.
       *  30.3.2 Namespace this_thread.
       */
      namespace this_thread
      {
        /// get_id
        inline thread::id
        get_id() noexcept
        {
    #ifdef __GLIBC__
          // For the GNU C library pthread_self() is usable without linking to
          // libpthread.so but returns 0, so we cannot use it in single-threaded
          // programs, because this_thread::get_id() != thread::id{} must be true.
          // We know that pthread_t is an integral type in the GNU C library.
          if (!__gthread_active_p())
    	return thread::id(1);
    #endif
          return thread::id(__gthread_self());
        }
    
        /// yield
        inline void
        yield() noexcept
        {
    #ifdef _GLIBCXX_USE_SCHED_YIELD
          __gthread_yield();
    #endif
        }
    
        void
        __sleep_for(chrono::seconds, chrono::nanoseconds);
    
        /// sleep_for
        template<typename _Rep, typename _Period>
          inline void
          sleep_for(const chrono::duration<_Rep, _Period>& __rtime)
          {
    	if (__rtime <= __rtime.zero())
    	  return;
    	auto __s = chrono::duration_cast<chrono::seconds>(__rtime);
    	auto __ns = chrono::duration_cast<chrono::nanoseconds>(__rtime - __s);
    #ifdef _GLIBCXX_USE_NANOSLEEP
    	__gthread_time_t __ts =
    	  {
    	    static_cast<std::time_t>(__s.count()),
    	    static_cast<long>(__ns.count())
    	  };
    	while (::nanosleep(&__ts, &__ts) == -1 && errno == EINTR)
    	  { }
    #else
    	__sleep_for(__s, __ns);
    #endif
          }
    
        /// sleep_until
        template<typename _Clock, typename _Duration>
          inline void
          sleep_until(const chrono::time_point<_Clock, _Duration>& __atime)
          {
    	auto __now = _Clock::now();
    	if (_Clock::is_steady)
    	  {
    	    if (__now < __atime)
    	      sleep_for(__atime - __now);
    	    return;
    	  }
    	while (__now < __atime)
    	  {
    	    sleep_for(__atime - __now);
    	    __now = _Clock::now();
    	  }
          }
      }
    
      // @} group threads
    
    _GLIBCXX_END_NAMESPACE_VERSION
    } // namespace
    
    #endif // _GLIBCXX_HAS_GTHREADS
    
    #endif // C++11
    
    #endif // _GLIBCXX_THREAD
    
    
  2. 新的thread头文件源代码:

    // <thread> -*- C++ -*-
    
    // Copyright (C) 2008-2018 Free Software Foundation, Inc.
    //
    // This file is part of the GNU ISO C++ Library.  This library is free
    // software; you can redistribute it and/or modify it under the
    // terms of the GNU General Public License as published by the
    // Free Software Foundation; either version 3, 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 General Public License for more details.
    
    // Under Section 7 of GPL version 3, you are granted additional
    // permissions described in the GCC Runtime Library Exception, version
    // 3.1, as published by the Free Software Foundation.
    
    // You should have received a copy of the GNU General Public License and
    // a copy of the GCC Runtime Library Exception along with this program;
    // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
    // <http://www.gnu.org/licenses/>.
    
    /** @file include/thread
     *  This is a Standard C++ Library header.
     */
    
    #ifndef _GLIBCXX_THREAD
    #define _GLIBCXX_THREAD 1
    
    #pragma GCC system_header
    
    #if __cplusplus < 201103L
    # include <bits/c++0x_warning.h>
    #else
    
    #include <chrono>
    #include <memory>
    #include <tuple>
    #include <cerrno>
    #include <bits/functexcept.h>
    #include <bits/functional_hash.h>
    #include <bits/invoke.h>
    #include <bits/gthr.h>
    
    #if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
    
    namespace std _GLIBCXX_VISIBILITY(default)
    {
    _GLIBCXX_BEGIN_NAMESPACE_VERSION
    
      /**
       * @defgroup threads Threads
       * @ingroup concurrency
       *
       * Classes for thread support.
       * @{
       */
    
      /// thread
      class thread
      {
      public:
        // Abstract base class for types that wrap arbitrary functors to be
        // invoked in the new thread of execution.
        struct _State
        {
          virtual ~_State();
          virtual void _M_run() = 0;
        };
        using _State_ptr = unique_ptr<_State>;
    
        typedef __gthread_t			native_handle_type;
    
        /// thread::id
        class id
        {
          native_handle_type	_M_thread;
    
        public:
          id() noexcept : _M_thread() { }
    
          explicit
          id(native_handle_type __id) : _M_thread(__id) { }
    
        private:
          friend class thread;
          friend class hash<thread::id>;
    
          friend bool
          operator==(thread::id __x, thread::id __y) noexcept;
    
          friend bool
          operator<(thread::id __x, thread::id __y) noexcept;
    
          template<class _CharT, class _Traits>
    	friend basic_ostream<_CharT, _Traits>&
    	operator<<(basic_ostream<_CharT, _Traits>& __out, thread::id __id);
        };
    
      private:
        id				_M_id;
    
      public:
        thread() noexcept = default;
        // _GLIBCXX_RESOLVE_LIB_DEFECTS
        // 2097.  packaged_task constructors should be constrained
        thread(thread&) = delete;
        thread(const thread&) = delete;
        thread(const thread&&) = delete;
    
        thread(thread&& __t) noexcept
        { swap(__t); }
    
        template<typename _Callable, typename... _Args>
          explicit
          thread(_Callable&& __f, _Args&&... __args)
          {
    #ifdef GTHR_ACTIVE_PROXY
    	// Create a reference to pthread_create, not just the gthr weak symbol.
    	auto __depend = reinterpret_cast<void(*)()>(&pthread_create);
    #else
    	auto __depend = nullptr;
    #endif
            _M_start_thread(_S_make_state(
    	      __make_invoker(std::forward<_Callable>(__f),
    			     std::forward<_Args>(__args)...)),
    	    __depend);
          }
    
        ~thread()
        {
          if (joinable())
    	std::terminate();
        }
    
        thread& operator=(const thread&) = delete;
    
        thread& operator=(thread&& __t) noexcept
        {
          if (joinable())
    	std::terminate();
          swap(__t);
          return *this;
        }
    
        void
        swap(thread& __t) noexcept
        { std::swap(_M_id, __t._M_id); }
    
        bool
        joinable() const noexcept
        { return !(_M_id == id()); }
    
        void
        join();
    
        void
        detach();
    
        thread::id
        get_id() const noexcept
        { return _M_id; }
    
        /** @pre thread is joinable
         */
        native_handle_type
        native_handle()
        { return _M_id._M_thread; }
    
        // Returns a value that hints at the number of hardware thread contexts.
        static unsigned int
        hardware_concurrency() noexcept;
    
      private:
        template<typename _Callable>
          struct _State_impl : public _State
          {
    	_Callable		_M_func;
    
    	_State_impl(_Callable&& __f) : _M_func(std::forward<_Callable>(__f))
    	{ }
    
    	void
    	_M_run() { _M_func(); }
          };
    
        void
        _M_start_thread(_State_ptr, void (*)());
    
        template<typename _Callable>
          static _State_ptr
          _S_make_state(_Callable&& __f)
          {
    	using _Impl = _State_impl<_Callable>;
    	return _State_ptr{new _Impl{std::forward<_Callable>(__f)}};
          }
    #if _GLIBCXX_THREAD_ABI_COMPAT
      public:
        struct _Impl_base;
        typedef shared_ptr<_Impl_base>	__shared_base_type;
        struct _Impl_base
        {
          __shared_base_type	_M_this_ptr;
          virtual ~_Impl_base() = default;
          virtual void _M_run() = 0;
        };
    
      private:
        void
        _M_start_thread(__shared_base_type, void (*)());
    
        void
        _M_start_thread(__shared_base_type);
    #endif
    
      private:
        // A call wrapper that does INVOKE(forwarded tuple elements...)
        template<typename _Tuple>
          struct _Invoker
          {
    	_Tuple _M_t;
    
    	template<size_t _Index>
    	  static __tuple_element_t<_Index, _Tuple>&&
    	  _S_declval();
    
    	template<size_t... _Ind>
    	  auto
    	  _M_invoke(_Index_tuple<_Ind...>)
    	  noexcept(noexcept(std::__invoke(_S_declval<_Ind>()...)))
    	  -> decltype(std::__invoke(_S_declval<_Ind>()...))
    	  { return std::__invoke(std::get<_Ind>(std::move(_M_t))...); }
    
    	using _Indices
    	  = typename _Build_index_tuple<tuple_size<_Tuple>::value>::__type;
    
    	auto
    	operator()()
    	noexcept(noexcept(std::declval<_Invoker&>()._M_invoke(_Indices())))
    	-> decltype(std::declval<_Invoker&>()._M_invoke(_Indices()))
    	{ return _M_invoke(_Indices()); }
          };
    
        template<typename... _Tp>
          using __decayed_tuple = tuple<typename std::decay<_Tp>::type...>;
    
      public:
        // Returns a call wrapper that stores
        // tuple{DECAY_COPY(__callable), DECAY_COPY(__args)...}.
        template<typename _Callable, typename... _Args>
          static _Invoker<__decayed_tuple<_Callable, _Args...>>
          __make_invoker(_Callable&& __callable, _Args&&... __args)
          {
    	return { __decayed_tuple<_Callable, _Args...>{
    	    std::forward<_Callable>(__callable), std::forward<_Args>(__args)...
    	} };
          }
      };
    
      inline void
      swap(thread& __x, thread& __y) noexcept
      { __x.swap(__y); }
    
      inline bool
      operator==(thread::id __x, thread::id __y) noexcept
      {
        // pthread_equal is undefined if either thread ID is not valid, so we
        // can't safely use __gthread_equal on default-constructed values (nor
        // the non-zero value returned by this_thread::get_id() for
        // single-threaded programs using GNU libc). Assume EqualityComparable.
        return __x._M_thread == __y._M_thread;
      }
    
      inline bool
      operator!=(thread::id __x, thread::id __y) noexcept
      { return !(__x == __y); }
    
      inline bool
      operator<(thread::id __x, thread::id __y) noexcept
      {
        // Pthreads doesn't define any way to do this, so we just have to
        // assume native_handle_type is LessThanComparable.
        return __x._M_thread < __y._M_thread;
      }
    
      inline bool
      operator<=(thread::id __x, thread::id __y) noexcept
      { return !(__y < __x); }
    
      inline bool
      operator>(thread::id __x, thread::id __y) noexcept
      { return __y < __x; }
    
      inline bool
      operator>=(thread::id __x, thread::id __y) noexcept
      { return !(__x < __y); }
    
      // DR 889.
      /// std::hash specialization for thread::id.
      template<>
        struct hash<thread::id>
        : public __hash_base<size_t, thread::id>
        {
          size_t
          operator()(const thread::id& __id) const noexcept
          { return std::_Hash_impl::hash(__id._M_thread); }
        };
    
      template<class _CharT, class _Traits>
        inline basic_ostream<_CharT, _Traits>&
        operator<<(basic_ostream<_CharT, _Traits>& __out, thread::id __id)
        {
          if (__id == thread::id())
    	return __out << "thread::id of a non-executing thread";
          else
    	return __out << __id._M_thread;
        }
    
      /** @namespace std::this_thread
       *  @brief ISO C++ 2011 entities sub-namespace for thread.
       *  30.3.2 Namespace this_thread.
       */
      namespace this_thread
      {
        /// get_id
        inline thread::id
        get_id() noexcept
        {
    #ifdef __GLIBC__
          // For the GNU C library pthread_self() is usable without linking to
          // libpthread.so but returns 0, so we cannot use it in single-threaded
          // programs, because this_thread::get_id() != thread::id{} must be true.
          // We know that pthread_t is an integral type in the GNU C library.
          if (!__gthread_active_p())
    	return thread::id(1);
    #endif
          return thread::id(__gthread_self());
        }
    
        /// yield
        inline void
        yield() noexcept
        {
    #ifdef _GLIBCXX_USE_SCHED_YIELD
          __gthread_yield();
    #endif
        }
    
        void
        __sleep_for(chrono::seconds, chrono::nanoseconds);
    
        /// sleep_for
        template<typename _Rep, typename _Period>
          inline void
          sleep_for(const chrono::duration<_Rep, _Period>& __rtime)
          {
    	if (__rtime <= __rtime.zero())
    	  return;
    	auto __s = chrono::duration_cast<chrono::seconds>(__rtime);
    	auto __ns = chrono::duration_cast<chrono::nanoseconds>(__rtime - __s);
    #ifdef _GLIBCXX_USE_NANOSLEEP
    	__gthread_time_t __ts =
    	  {
    	    static_cast<std::time_t>(__s.count()),
    	    static_cast<long>(__ns.count())
    	  };
    	while (::nanosleep(&__ts, &__ts) == -1 && errno == EINTR)
    	  { }
    #else
    	__sleep_for(__s, __ns);
    #endif
          }
    
        /// sleep_until
        template<typename _Clock, typename _Duration>
          inline void
          sleep_until(const chrono::time_point<_Clock, _Duration>& __atime)
          {
    	auto __now = _Clock::now();
    	if (_Clock::is_steady)
    	  {
    	    if (__now < __atime)
    	      sleep_for(__atime - __now);
    	    return;
    	  }
    	while (__now < __atime)
    	  {
    	    sleep_for(__atime - __now);
    	    __now = _Clock::now();
    	  }
          }
      }
    
      // @} group threads
    
    _GLIBCXX_END_NAMESPACE_VERSION
    } // namespace
    
    #endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1
    
    #endif // C++11
    
    #endif // _GLIBCXX_THREAD
    
    
  • 66
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值