Reference: https://github.com/forhappy/Cplusplus-Concurrency-In-Practice/blob/master/zh/chapter3-Thread/ Introduction-to-thread.md#stdthread-%e8%af%a6%e8%a7%a3
This section describes std::thread
the usage in detail.
std::thread
is <thread>
declared in the header file, so the use std::thread
needs to include the <thread>
header file.
<thread>
Header File Summary
<thread>
The header file declares the Std::thread thread class and std::swap
(Swaps two thread objects) auxiliary functions. In addition std::this_thread
, the namespace is declared in the <thread>
header file. The following is a summary of the header files defined by the C++11 standard <thread>
:
See draft n3242=11-0012 section 30.3, Threads (p1133).
namespace std { #define __STDCPP_THREADS__ __cplusplus class thread; void swap(thread& x, thread& y); namespace this_thread { thread::id get_id(); void yield(); template <class Clock, class Duration> void sleep_until(const chrono::time_point<Clock, Duration>& abs_time); template <class Rep, class Period> void sleep_for(const chrono::duration<Rep, Period>& rel_time); } }
<thread>
The header file mainly declares the std::thread
class, in addition to the std::this_thread
namespace declaration get_id
, yield
as well as the sleep_until
sleep_for
auxiliary functions, this chapter will be a little more detailed description std::thread
of the class and related functions.
std::thread
Class Summary
std::thread
Represents a thread object, the C++11 standard declares as follows:
namespace std {class Thread {public://type declaration: Class ID; typedef implementation-defined NATIVE_HANDLE_TYPE; constructors, copy constructors, and destructor declarations: thread () noexcept; Template <class F, class ... args> Explicit Thread (f&& F, Args&& .... Args); ~thread (); Thread (const thread&) = delete; Thread (thread&&) noexcept; thread& operator= (const thread&) = delete; thread& operator= (thread&&) noexcept; member function declaration: void swap (thread&) noexcept; BOOL Joinable () const noexcept; void join (); void Detach (); ID get_id () const noexcept; Native_handle_type Native_handle (); Static member function declaration: Static unsigned hardware_concurrency () noexcept; };}
std::thread
The main declaration of three kinds of functions: (1). constructors, copy constructors, and destructors; (2). member function; (3). static member functions. Also, the std::thread::id
thread ID is represented, and the c++11 is declared as follows:
namespace std { class thread::id { public: id() noexcept; }; bool operator==(thread::id x, thread::id y) noexcept; bool operator!=(thread::id x, thread::id y) noexcept; bool operator<(thread::id x, thread::id y) noexcept; bool operator<=(thread::id x, thread::id y) noexcept; bool operator>(thread::id x, thread::id y) noexcept; bool operator>=(thread::id x, thread::id y) noexcept; template<class charT, class traits> basic_ostream<charT, traits>& operator<< (basic_ostream<charT, traits>& out, thread::id id); // Hash 支持 template <class T> struct hash; template <> struct hash<thread::id>;}
std::thread
Detailed
std::thread
Construct and assign values
std::thread
constructor function
Default constructor (1) |
Thread () noexcept; |
Initializing Constructors (2) |
Template <class Fn, class ... Args> Explicit thread (fn&& Fn, Args&& .... Args); |
copy constructor [deleted] (3) |
Thread (const thread&) = delete; |
Move Constructor (4) |
Thread (thread&& x) noexcept; |
- The default constructor (1) Creates an empty
std::thread
execution object.
- Initializes the constructor (2), creates an
std::thread
object that can be std::thread
, the joinable
newly generated thread invokes the fn
function, and the function's arguments are given by args
.
- The copy Constructor (disabled) (3) means that the
std::thread
object is non-copy constructed.
- The move constructor (4), the move constructor (move semantics is the new concept of c++11, as described in the appendix),
x
does not represent any execution object after the call succeeds std::thread
.
Note: Objects that can be used joinable
std::thread
must be either the main thread join
or set to before they are destroyed detached
.
Std::thread examples of various constructors are as follows (reference):
#include <iostream>#include <utility>#include <thread>#include <chrono>#include <functional>#include <atomic>void f1(int n){ for (int i = 0; i < 5; ++i) { std::cout << "Thread " << n << " executing\n"; std::this_thread::sleep_for(std::chrono::milliseconds(10)); }}void f2(int& n){ for (int i = 0; i < 5; ++i) { std::cout << "Thread 2 executing\n"; ++n; std::this_thread::sleep_for(std::chrono::milliseconds(10)); }}int main(){ int n = 0; std::thread t1; // t1 is not a thread std::thread t2(f1, n + 1); // pass by value std::thread t3(f2, std::ref(n)); // pass by reference std::thread t4(std::move(t3)); // t4 is now running f2(). t3 is no longer a thread t2.join(); t4.join(); std::cout << "Final value of n is " << n << ‘\n‘;}
std::thread
Assignment operation
Move Assignment Action (1) |
thread& operator= (thread&& rhs) noexcept; |
Copy assignment operation [deleted] (2) |
thread& operator= (const thread&) = delete; |
- The Move Assignment Action (1), if the current object is not available
joinable
, needs to pass an rvalue reference ( rhs
) to the move
assignment operation, or joinable
() An error if the current object is available terminate
.
- The Copy assignment operation (2) is disabled, so the
std::thread
object cannot be copied and assigned to the value.
Take a look at the following example:
#include <stdio.h>#include <stdlib.h>#include <chrono> // std::chrono::seconds#include <iostream> // std::cout#include <thread> // std::thread, std::this_thread::sleep_forvoid thread_task(int n) { std::this_thread::sleep_for(std::chrono::seconds(n)); std::cout << "hello thread " << std::this_thread::get_id() << " paused " << n << " seconds" << std::endl;}int main(int argc, const char *argv[]){ std::thread threads[5]; std::cout << "Spawning 5 threads...\n"; for (int i = 0; i < 5; i++) { threads[i] = std::thread(thread_task, i + 1); } std::cout << "Done spawning threads! Now wait for them to join\n"; for (auto& t: threads) { t.join(); } std::cout << "All threads joined.\n"; return EXIT_SUCCESS;}
Other member functions
The example in this section comes from http://en.cppreference.com
-
get_id
: Gets the thread ID that returns an object of type std::thread::id
. Take a look at the following example:
#include <iostream> #include <thread> #include <chrono>void foo () {Std::this_ Thread::sleep_for (Std::chrono::seconds (1));} int main () {std::thread T1 (foo); Std::thread::id t1_id = t1.get_id (); Std::thread T2 (foo); Std::thread::id t2_id = t2.get_id (); Std::cout << "T1 ' s ID:" << t1_id << ' \ n '; Std::cout << "T2 ' s ID:" << t2_id << ' \ n '; T1.join (); T2.join ();}
-
joinable
: Checks whether a thread can be join. Checks whether the current thread object represents an active execution thread, and the thread created by the default constructor cannot be join. In addition, if a thread has finished the task but is not being join, the thread will still be considered an active thread of execution and therefore can be join.
#include <iostream> #include <thread> #include <chrono>void foo () {std::this_thread: : Sleep_for (Std::chrono::seconds (1));} int main () {Std::thread T; Std::cout << "Before starting, joinable:" << t.joinable () << ' \ n '; t = Std::thread (foo); Std::cout << "After starting, joinable:" << t.joinable () << ' \ n '; T.join ();}
join
: The join thread, which calls the function to block the current thread until the *this
indicated thread has finished executing the join before returning.
#include <iostream>#include <thread>#include <chrono>void foo(){ // simulate expensive operation std::this_thread::sleep_for(std::chrono::seconds(1));}void bar(){ // simulate expensive operation std::this_thread::sleep_for(std::chrono::seconds(1));}int main(){ std::cout << "starting first helper...\n"; std::thread helper1(foo); std::cout << "starting second helper...\n"; std::thread helper2(bar); std::cout << "waiting for helpers to finish..." << std::endl; helper1.join(); helper2.join(); std::cout << "done!\n";}
detach
: Detach thread. Separates the execution instance represented by the current thread object from the thread object, allowing the execution of the thread to be performed independently. Once the thread has finished executing, the resources it allocates will be freed.
After calling the Detach function:
*this
Instances are no longer executed on behalf of any thread.
- joinable () = = False
- get_id () = = Std::thread::id ()
In addition, if there is an error or joinable() == false
, it will be thrown std::system_error
.
#include <iostream> #include <chrono> #include <thread> void independentThread() { std::cout << "Starting concurrent thread.\n"; std::this_thread::sleep_for(std::chrono::seconds(2)); std::cout << "Exiting concurrent thread.\n"; } void threadCaller() { std::cout << "Starting thread caller.\n"; std::thread t(independentThread); t.detach(); std::this_thread::sleep_for(std::chrono::seconds(1)); std::cout << "Exiting thread caller.\n"; } int main() { threadCaller(); std::this_thread::sleep_for(std::chrono::seconds(5)); }
swap
: Swap thread, swapping the underlying handle represented by two thread objects (underlying handles).
#include <iostream>#include <thread>#include <chrono>void foo(){ std::this_thread::sleep_for(std::chrono::seconds(1));}void bar(){ std::this_thread::sleep_for(std::chrono::seconds(1));}int main(){ std::thread t1(foo); std::thread t2(bar); std::cout << "thread 1 id: " << t1.get_id() << std::endl; std::cout << "thread 2 id: " << t2.get_id() << std::endl; std::swap(t1, t2); std::cout << "after std::swap(t1, t2):" << std::endl; std::cout << "thread 1 id: " << t1.get_id() << std::endl; std::cout << "thread 2 id: " << t2.get_id() << std::endl; t1.swap(t2); std::cout << "after t1.swap(t2):" << std::endl; std::cout << "thread 1 id: " << t1.get_id() << std::endl; std::cout << "thread 2 id: " << t2.get_id() << std::endl; t1.join(); t2.join();}
The results of the implementation are as follows:
thread 1 id: 1892thread 2 id: 2584after std::swap(t1, t2):thread 1 id: 2584thread 2 id: 1892after t1.swap(t2):thread 1 id: 1892thread 2 id: 2584
native_handle
: Returns native handle (because std::thread
the implementation is related to the operating system, the function returns the thread handle associated with the std::thread
implementation, for example, under the Posix-compliant platform (such as Unix/linux) is the Pthread library).
#include <thread>#include <iostream>#include <chrono>#include <cstring>#include <pthread.h>std::mutex iomutex;void f(int num){ std::this_thread::sleep_for(std::chrono::seconds(1)); sched_param sch; int policy; pthread_getschedparam(pthread_self(), &policy, &sch); std::lock_guard<std::mutex> lk(iomutex); std::cout << "Thread " << num << " is executing at priority " << sch.sched_priority << ‘\n‘;}int main(){ std::thread t1(f, 1), t2(f, 2); sched_param sch; int policy; pthread_getschedparam(t1.native_handle(), &policy, &sch); sch.sched_priority = 20; if(pthread_setschedparam(t1.native_handle(), SCHED_FIFO, &sch)) { std::cout << "Failed to setschedparam: " << std::strerror(errno) << ‘\n‘; } t1.join(); t2.join();}
The results of the implementation are as follows:
Thread 2 is executing at priority 0Thread 1 is executing at priority 20
hardware_concurrency
[Static]: detects hardware concurrency and returns the number of thread concurrency supported by the current platform's thread implementation, but the return value is only used as a system hint (hint).
#include <iostream>#include <thread>int main() { unsigned int n = std::thread::hardware_concurrency(); std::cout << n << " concurrent threads are supported.\n";}
std::this_thread
Introduction to related helper functions in namespaces
-
get_id: Gets the thread ID.
#include <iostream> #include <thread> #include <chrono> #include <mutex>std:: Mutex g_display_mutex;void foo () {Std::thread::id this_id = std::this_thread::get_id (); G_display_mutex.lock (); Std::cout << "Thread" << this_id << "sleeping...\n"; G_display_mutex.unlock (); Std::this_thread::sleep_for (Std::chrono::seconds (1));} int main () {std::thread T1 (foo); Std::thread T2 (foo); T1.join (); T2.join ();}
-
Yield: The current thread discards execution, and the operating system dispatches another thread to continue execution.
#include <iostream> #include <chrono> #include <thread>//"Busy sleep" while Suggesting that and threads run//For a small amount of timevoid little_sleep (std::chrono::microseconds us) {Auto St Art = Std::chrono::high_resolution_clock::now (); Auto End = start + us; do {Std::this_thread::yield (); } while (Std::chrono::high_resolution_clock::now () < end);} int main () {Auto start = Std::chrono::high_resolution_clock::now (); Little_sleep (std::chrono::microseconds (100)); Auto elapsed = Std::chrono::high_resolution_clock::now ()-Start; Std::cout << "waited for" << Std::chrono::d uration_cast<std::chrono::microseconds> (elapsed ). Count () << "microseconds\n";}
Sleep_until: The thread sleeps to a specified moment (time point) before it wakes up again.
template< class Clock, class Duration >void sleep_until( const std::chrono::time_point<Clock,Duration>& sleep_time );
Sleep_for: The thread sleeps on a specified time span, and the thread is woken up, but the actual sleep time may be longer than the time slice represented, for reasons such as thread scheduling sleep_duration
.
template< class Rep, class Period >void sleep_for( const std::chrono::duration<Rep,Period>& sleep_duration );#include <iostream>#include <chrono>#include <thread>int main(){ std::cout << "Hello waiter" << std::endl; std::chrono::milliseconds dura( 2000 ); std::this_thread::sleep_for( dura ); std::cout << "Waited 2000 ms\n";}
The results of the implementation are as follows:
Hello waiterWaited 2000 ms
c++11 Concurrency Guide------std::thread detailed