前言:
如今小伙伴们对“c语言beginthread”大致比较注重,各位老铁们都需要分析一些“c语言beginthread”的相关资讯。那么小编在网络上网罗了一些关于“c语言beginthread””的相关资讯,希望姐妹们能喜欢,小伙伴们一起来了解一下吧!1、std::thread (C++11)
std::thread 表示一个线程,在构造时开始线程执行。
1.1、基本使用
std::thread 默认构造函数 (1) 不会创建任何线程;拷贝构造函数 (4) 是删除的,不允许通过拷贝创建一个 std::thread 对象;但是移动构造函数是可以使用的,other 在移动后不代表一个线程。
thread() noexcept; // (1)thread( thread&& other ) noexcept; // (2)template< class Function, class... Args >explicit thread( Function&& f, Args&&... args ); // (3)thread( const thread& ) = delete; // (4)
构造函数 (3) 接受一个可调用对象 f,以及传递参数给 f。函数参数是模板参数右值引用类型,可以接受左值和右值。
#include <iostream>#include <thread>class Foo { public: static void Bar1(const char* msg) { std::cout << "Bar1 executing: " << msg << std::endl; } void Bar2(const char* msg) { std::cout << "Bar2 executing: " << msg << std::endl; }};int main() { Foo foo; std::thread t1(Foo::Bar1, "thread1"); std::thread t2(&Foo::Bar2, &foo, "thread2"); t1.join(); t2.join(); return 0;}
当线程构造完成,可以调用 joinable() 判断是否正在执行,或调用 join() 等待线程执行结束,也可以调用 detach() 让线程后台执行,用户需要确保线程后台执行时,访问的资源不会被释放。
jion() 和 detach() 调用返回后,joinable() 返回 false。
#include <stdio.h>#include <chrono>#include <thread>class Foo { public: static void Bar1(const char* msg) { for (int i = 0; i < 5; ++i) { printf("%s executing... #%d\n", msg, i); std::this_thread::sleep_for(std::chrono::milliseconds(50)); } } static void Bar2(const char* msg) { printf("%s begin\n", msg); std::thread bg(Foo::Bar1, "bgthread"); bg.detach(); printf("bg joinable %d\n", bg.joinable()); printf("%s end\n", msg); }};int main() { std::thread t1(Foo::Bar2, "thread1"); printf("t1 joinable %d\n", t1.joinable()); t1.join(); printf("t1 joinable %d\n", t1.joinable()); std::this_thread::sleep_for(std::chrono::seconds(1)); return 0;}
输出为
t1 joinable 1thread1 beginbg joinable 0thread1 endbgthread executing... #0t1 joinable 0bgthread executing... #1bgthread executing... #2bgthread executing... #3bgthread executing... #4
std::thread 还支持赋值操作,但是 other 必须时右值。如果 *this 没有绑定到线程,就将 other 的状态赋值给 *this,否则 std::terminate() 将会调用。
thread& operator=( thread&& other ) noexcept;
比如下面的例子,t1 使用默认构造函数,没有绑定任何线程,t2 可以转移给 t1。当 t3 已经绑定线程,正在执行,将 t4 绑定到 t3 时,会出现错误。
#include <stdio.h>#include <chrono>#include <thread>class Foo { public: static void Bar1(const char* msg) { for (int i = 0; i < 5; ++i) { printf("%s executing... #%d\n", msg, i); std::this_thread::sleep_for(std::chrono::milliseconds(50)); } }};int main() { std::thread t1; std::thread t2(Foo::Bar1, "thread1"); t1 = std::move(t2); printf("t2 joinable %d\n", t2.joinable()); t1.join(); std::thread t3(Foo::Bar1, "thread3"); std::thread t4(Foo::Bar1, "thread4"); t3 = std::move(t4); t3.join(); return 0;}
输出结果为
t2 joinable 0thread1 executing... #0thread1 executing... #1thread1 executing... #2thread1 executing... #3thread1 executing... #4thread3 executing... #0terminate called without an active exceptionthread4 executing... #0Aborted
最后,可以使用 get_id() 返回线程 id,标记一个 id。如果使用赋值转移 thread 给所有权,id 也是会转移的。
std::thread::id get_id() const noexcept;
也可以使用 std::this_thread::get_id() 来获取当前线程的 id。另外std::this_thread 提供 yeild/sleep_for/sleep_until() 等函数,可以主动让出 CPU,让其他线程使用 CPU,操作系统再次调度获取 CPU 后继续执行。
1.2、底层实现1.2.1、std::thread::id
thread::id 有一个数据成员 _M_thread,Linux 系统中,就是 pthread_t
/// std_thread.h class id { native_handle_type _M_thread; public: id() noexcept : _M_thread() { } explicit id(native_handle_type __id) : _M_thread(__id) { } private://... };1.2.2、std::thread::_State
_State 用于封装一个 functor,创建线程后,线程调用 _M_run() 函数。_State 是一个虚基类,_State_impl 是其实现类。
_State_impl 只有一个 _Callable 类型的成员变量 _M_func,其包装了调用参数,可以直接调用执行 _M_func()
/// std_thread.h struct _State { virtual ~_State(); virtual void _M_run() = 0; }; using _State_ptr = unique_ptr<_State>;/// impl template<typename _Callable> struct _State_impl : public _State { _Callable _M_func; template<typename... _Args> _State_impl(_Args&&... __args) : _M_func{{std::forward<_Args>(__args)...}} { } void _M_run() { _M_func(); } };
_State_impl 模板函数 _Callable 是 _Invoker 类。_Invoker 重载了函数调用符 (),调用 std::__invoke() 函数,触发传入的 functor 以及参数。
/// std_thread.h 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()); } }; using _Call_wrapper = _Invoker<tuple<typename decay<_Tp>::type...>>;1.2.3、std::thread
std::thread 一个成员变量,_M_id,表示线程 id
/// std_thread.h class thread { public: using native_handle_type = __gthread_t; private: id _M_id;// ... };
当传入 functor 和参数时,调用如下构造函数,然后调用 _M_start_thread() 函数。
/// std_thread.h#ifdef _GLIBCXX_HAS_GTHREADS 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 using _Wrapper = _Call_wrapper<_Callable, _Args...>; // Create a call wrapper with DECAY_COPY(__f) as its target object // and DECAY_COPY(__args)... as its bound argument entities. _M_start_thread(_State_ptr(new _State_impl<_Wrapper>( std::forward<_Callable>(__f), std::forward<_Args>(__args)...)), __depend); }#endif // _GLIBCXX_HAS_GTHREADS
_M_start_thread() 函数利用操作系统接口创建一个线程,线程执行 execute_native_thread_routine() 函数
/// thread.cc void thread::_M_start_thread(_State_ptr state, void (*)()) { if (!__gthread_active_p()) {#if __cpp_exceptions throw system_error(make_error_code(errc::operation_not_permitted), "Enable multithreading to use std::thread");#else __builtin_abort();#endif } const int err = __gthread_create(&_M_id._M_thread, &execute_native_thread_routine, state.get()); if (err) __throw_system_error(err); state.release(); }
execute_native_thread_routine() 其实就是调用 _State_impl::_M_run() 函数,触发用于指定的 functor 以及 args。
/// thread.c static void* execute_native_thread_routine(void* __p) { thread::_State_ptr __t{ static_cast<thread::_State*>(__p) }; __t->_M_run(); return nullptr; }
join() 和 detach() 函数也是分别调用操作系统函数执行,最后将 _M_id 赋值为 id(),表示 std::thread 已经不绑定到任何线程。
/// thread.cc void thread::join() { int __e = EINVAL; if (_M_id != id()) __e = __gthread_join(_M_id._M_thread, 0); if (__e) __throw_system_error(__e); _M_id = id(); } void thread::detach() { int __e = EINVAL; if (_M_id != id()) __e = __gthread_detach(_M_id._M_thread); if (__e) __throw_system_error(__e); _M_id = id(); }1.2.4、std::this_thread
this_thread 并不是一个类,而是命名空间。get_id() 和 yield() 函数分别调用 pthread_self() 和 sched_yield(),后者 sched_yield() 是 Linux 系统调用。
/// std_thread.hnamespace this_thread { inline thread::id get_id() noexcept {#ifndef _GLIBCXX_HAS_GTHREADS// ...#elif defined _GLIBCXX_NATIVE_THREAD_ID return thread::id(_GLIBCXX_NATIVE_THREAD_ID); // pthread_self()#else// ...#endif } inline void yield() noexcept {#if defined _GLIBCXX_HAS_GTHREADS && defined _GLIBCXX_USE_SCHED_YIELD __gthread_yield(); // sched_yield()#endif } } // namespace this_thread
sleep_for() 函数底层调用 nanosleep() 函数 (libc),时间粒度是纳秒级。sleep_until() 函数是借助 sleep_for() 函数实现的。
/// this_thread_sleep.h namespace this_thread { /// this_thread::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 struct ::timespec __ts = { static_cast<std::time_t>(__s.count()), static_cast<long>(__ns.count()) }; while (::nanosleep(&__ts, &__ts) == -1 && errno == EINTR) { }#else// ...#endif } /// this_thread::sleep_until template<typename _Clock, typename _Duration> inline void sleep_until(const chrono::time_point<_Clock, _Duration>& __atime) {#if __cplusplus > 201703L static_assert(chrono::is_clock_v<_Clock>);#endif 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(); } } } // namespace this_thread
标签: #c语言beginthread