cpp►C++11标准线程库<thread>
Posted itzyjr
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cpp►C++11标准线程库<thread>相关的知识,希望对你有一定的参考价值。
thread类
std::thread
class thread
thread类用来表示各个执行线程(threads of execution)。
一个执行线程是一个指令序列,它可以在多线程环境中与其他这样的序列同时执行,同时共享相同的地址空间。
一个初始化的线程对象表示正在执行的活动线程; 这样的线程对象是joinable(可接合的),并且具有惟一的线程id(thread id)。
一个默认构造的(未初始化的)线程对象是not joinable的,其线程id对所有non-joinable线程都是通用的。
如果从joinable线程中移动,或者对其调用join或detach,则joinable线程将变成not joinable。
注意:可被 joinable 的 std::thread 对象必须在他们销毁之前被主线程 join 或者将其设置为 detached。
成员类型
- id:
std::thread::id
(public member type)
class thread::id
该类型的值由thread::get_id和this_thread::get_id返回来标识线程。
默认构造的thread::id对象的值标识non-joinable线程,因此通过比较会等于任何此类线程的成员thread::get_id返回的值。
对于joinable线程,thread::get_id返回该类型的唯一值,该值与任何其他joinable或non-joinable线程的返回值不相等。
注意,某些库实现可能会重用终止线程的thread::id值,该线程不能再能被join。
成员函数:
id() noexcept;// default constructor
构造表示所有non-joinable线程的thread::id值。线程::id对象是可复制的。 - native_handle_type:
std::thread::native_handle_type
(public member type)
`typedef /* implementation-defined */ native_handle_type;
这个成员类型只有在库实现支持它的情况下才出现在类线程中。
它是thread::native_handle返回的类型,带有关于线程的特定实现信息。
成员函数
- 构造函数
- 析构函数
- operator=:移动赋值线程
- get_id
获取线程 ID,返回一个类型为 std::thread::id 的对象。
如果线程对象是joinable,则函数返回一个唯一标识线程的值。
如果线程对象是non-joinable,函数返回成员类型thread::id的默认构造对象。
// thread::get_id / this_thread::get_id
#include <iostream>// std::cout
#include <thread>// std::thread, std::thread::id, std::this_thread::get_id
#include <chrono>// std::chrono::seconds
std::thread::id main_thread_id = std::this_thread::get_id();
void is_main_thread() {
if (main_thread_id == std::this_thread::get_id())
std::cout << "This is the main thread.\\n";
else
std::cout << "This is not the main thread.\\n";
}
int main() {
is_main_thread();
std::thread th(is_main_thread);
th.join();
}
This is the main thread.
This is not the main thread.
#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();
}
t1's id: 11804
t2's id: 15652
- joinable
std::thread::joinable
bool joinable() const noexcept;
如果一个线程对象表示一个执行线程,那么它就是joinable的。
检查线程是否可被 join。检查当前的线程对象是否表示了一个活动的执行线程,由默认构造函数创建的线程是不能被 join 的。另外,如果某个线程 已经执行完任务,但是没有被 join 的话,该线程依然会被认为是一个活动的执行线程,因此也是可以被 join 的。
在以下任何一种情况下,线程对象都是non-joinable的:
- 如果它是默认构造的。
- 如果它已经(构造另一个线程对象,或赋值给它)。
- 如果它的任何一个成员被调用了join或detach。
Join线程:调用该函数会阻塞当前线程,直到由*this 所标示的线程执行完毕 join才返回。
// example for thread::joinable
#include <iostream>// std::cout
#include <thread>// std::thread
void mythread() {
// do stuff...
}
int main() {
std::thread foo;
std::thread bar(mythread);
std::cout << "Joinable after construction:\\n" << std::boolalpha;
std::cout << "foo: " << foo.joinable() << '\\n';
std::cout << "bar: " << bar.joinable() << '\\n';
if (foo.joinable()) foo.join();
if (bar.joinable()) bar.join();
std::cout << "Joinable after joining:\\n" << std::boolalpha;
std::cout << "foo: " << foo.joinable() << '\\n';
std::cout << "bar: " << bar.joinable() << '\\n';
return 0;
}
输出:
Joinable after construction:
foo: false
bar: true
Joinable after joining:
foo: false
bar: false
- join
std::thread::join
void join();
当线程执行完成时,函数返回。
这会阻塞调用该函数的线程的执行,直到构造函数调用的函数返回(如果还没有返回的话)。
调用此函数后,线程对象就变成non-joinable,可以安全地销毁。
// example for thread::join
#include <iostream>// std::cout
#include <thread>// std::thread, std::this_thread::sleep_for
#include <chrono>// std::chrono::seconds
void pause_thread(int n) {
std::this_thread::sleep_for(std::chrono::seconds(n));
std::cout << "pause of " << n << " seconds ended\\n";
}
int main() {
std::cout << "Spawning 3 threads...\\n";
std::thread t1(pause_thread, 1);//【断点,立即执行】
std::thread t2(pause_thread, 2);//【断点,立即执行】
std::thread t3(pause_thread, 3);//【断点,立即执行】
std::cout << "Done spawning threads. Now waiting for them to join:\\n";
t1.join();//【断点,跳转到pause_thread函数里执行完毕后继续下面代码】
t2.join();//【断点,跳转到pause_thread函数里执行完毕后继续下面代码】
t3.join();//【断点,跳转到pause_thread函数里执行完毕后继续下面代码】
std::cout << "All threads joined!\\n";
return 0;
}
输出:
Spawning 3 threads...【立即】
Done spawning threads. Now waiting for them to join:【立即】
pause of 1 seconds ended【1秒后】
pause of 2 seconds ended【2秒后】
pause of 3 seconds ended【3秒后】
All threads joined!【3秒后立即】
t1、t2、t3在构造函数初始化后,立即执行,即3个sleep_for函数并行执行。调用join函数,保证在当前线程调用的函数pause_thread执行完毕前不执行当前线程,在此即阻塞主线程。pause_thread执行完毕,线程对象就变成non-joinable,可以安全地销毁。接下来就是主线程下面的语句接着执行。
如果注释掉3个join();函数调用,则输出如下(有abort异常忽略掉):
Spawning 3 threads...【立即】
Done spawning threads. Now waiting for them to join:【立即】
All threads joined!【立即】
pause of 1 seconds ended【1秒后】
pause of 2 seconds ended【2秒后】
pause of 3 seconds ended【3秒后】
- detach
std::thread::detach
void detach();
将对象所表示的线程与调用线程分离(detach),允许它们彼此独立执行。
两个线程继续运行,没有阻塞或以任何方式同步。 请注意,当任何一个结束执行时,它的资源都会被释放。
调用此函数后,线程对象就变成non-joinable,可以安全地销毁。
Detach 线程。 将当前线程对象所代表的执行实例与该线程对象分离,使得线程的执行可以单独进行。一旦线程执行完毕,它所分配的资源将会被释放。
调用 detach 函数之后:
*this 不再代表任何的线程执行实例;
joinable() == false;
get_id() == std::thread::id();
另外,如果出错或者 joinable() == false,则会抛出 std::system_error。
#include <iostream>// std::cout
#include <thread>// std::thread, std::this_thread::sleep_for
#include <chrono>// std::chrono::seconds
void pause_thread(int n) {
std::this_thread::sleep_for(std::chrono::seconds(n));
std::cout << "pause of " << n << " seconds ended\\n";
}
int main() {
std::cout << "Spawning and detaching 3 threads...\\n";
std::thread(pause_thread, 1).detach();
std::thread(pause_thread, 2).detach();
std::thread(pause_thread, 3).detach();
std::cout << "Done spawning threads.\\n";
std::cout << "(the main thread will now pause for 5 seconds)\\n";
// give the detached threads time to finish (but not guaranteed!):
pause_thread(5);
return 0;
}
Spawning and detaching 3 threads...【立即】
Done spawning threads.【立即】
(the main thread will now pause for 5 seconds)【立即】
pause of 1 seconds ended【1秒后】
pause of 2 seconds ended【2秒后】
pause of 3 seconds ended【3秒后】
pause of 5 seconds ended【5秒后】
如果注释掉最后的pause_thread(5); 则运行结果如下:
Spawning and detaching 3 threads...【立即】
Done spawning threads.【立即】
(the main thread will now pause for 5 seconds)【立即】
即程序已经结束,线程已被销毁,还没等到sleep_for函数执行完毕就已经结束了。
#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));
}
Starting thread caller.【立即】
Starting concurrent thread.【立即】
Exiting thread caller.【1秒后】
Exiting concurrent thread.【2秒后】
【5秒后结束】
命名空间std::this_thread下的4个函数
namespace std::this_thread
这个命名空间对访问当前线程的一组函数进行分组。
函数:
➀get_id:thread::id get_id() noexcept;
返回调用线程的线程id。这个值唯一地标识线程。
➁yield:void yield() noexcept;
当前线程放弃执行,操作系统调度另一线程继续执行。
调用线程放弃,提供实现重新调度的机会。
当一个线程在不阻塞的情况下等待其他线程前进时,该函数将被调用。
// this_thread::yield example
#include <iostream>// std::cout
#include <thread>// std::thread, std::this_thread::yield
#include <atomic>// std::atomic
std::atomic<bool> ready(false);
void count1m(int id) {
while (!ready) {// wait until main() sets ready...
std::this_thread::yield();
}
for (volatile int i=0; i<1000000; ++i) {}
std::cout << id << ' ';
}
int main () {
std::thread threads[10];
std::cout << "race of 10 threads that count to 1 million:\\n";
for (int i=0; i<10; ++i)
threads[i] = std::thread(count1m, i);
ready = true;// go!
for (auto& th : threads)
th.join();// 若不调用线程的join()阻塞当前线程,则return 0;还没等线程执行完,就立即将线程销毁掉了。
std::cout << '\\n';
return 0;
}
race of 10 threads that count to 1 million:
0 4 3 7 8 2 1 5 6 9
#include <iostream>
#include <chrono>
#include <thread>
// "busy sleep" while suggesting that other threads run for a small amount of time
void little_sleep(std::chrono::microseconds us) {
auto start = 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();
// 1×microseconds(微秒)=1000×milliseconds(毫秒)=1000×seconds(秒)
little_sleep(std::chrono::microseconds(5 * 1000 * 1000));
auto elapsed = std::chrono::high_resolution_clock::now() - start;
std::cout << "waited for "
<< std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count()
<< " microseconds\\n";
}
waited for 5000009 microseconds【5秒后】
➂sleep_until:
template <class Clock, class Duration>
void sleep_until(const chrono::time_point<Clock, Duration>& abs_time);
阻塞调用线程直到abs_time。
当前线程的执行将至少停止到abs_time,而其他线程可能继续前进。
参数abs_time: 调用线程恢复其执行的时间点。
请注意,多线程管理操作可能会导致超出此范围的某些延迟。
time_point是一个表示特定绝对时间的对象。
// this_thread::sleep_for example
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>// std::cout
#include <iomanip>// std::put_time
#include <thread>// std::this_thread::sleep_until
#include <chrono>// std::chrono::system_clock
#include <ctime>// std::time_t, std::tm, std::localtime, std::mktime
int main() {
using std::chrono::system_clock;
std::time_t tt = system_clock::to_time_t(system_clock::now());
struct std::tm* ptm = std::localtime(&tt);
std::cout << "Current time: " << std::put_time(ptm, "%X") << '\\n';
std::cout << "Waiting for the next minute to begin...\\n";
++ptm->tm_min;// 注:成员选择(指针)运算符->优先级高于自增运算符++
ptm->tm_sec = 0;
std::this_thread::sleep_until(system_clock::from_time_t(mktime(ptm)));
std::cout << std::put_time(ptm, "%X") << " reached!\\n";
return 0;
}
Current time: 19:51:07
Waiting for the next minute to begin...
19:52:00 reached!【大约1分钟后】
➃sleep_for
template <class Rep, class Period>
void sleep_for(const chrono::duration<Rep, Period>& rel_time);
在rel_time指定的时间范围内阻塞调用线程的执行。
当前线程的执行将停止,直到从现在起至少通过rel_time。 其他线程继续执行它们。
// this_thread::sleep_for example
#include <iostream>// std::cout, std::endl
#include <thread>// std::this_thread::sleep_for
#include <chrono>// std::chrono::seconds
int main() {
std::cout << "countdown:\\n";
for (int i = 10; i > 0; --i) {
std::cout << i << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
std::cout << "Lift off!\\n";
return 0;
}
countdown:【立即】
10【立即】
9【1秒后】
8【再1秒后】
7【再1秒后】
6【再1秒后】
5【再1秒后】
4【再1秒后】
3【再1秒后】
2【再1秒后】
1【再1秒后】
Lift off!
C++11 std::async基本用法
std::async
是std::future
的高级封装,一般我们不会直接使用std::futrue,而是使用对std::future的高级封装std::async。下面分别说一下。
// async example
#include <iostream>// std::cout
#include <future>// std::async, std::future
// a non-optimized way of checking for prime numbers(素数):
bool is_prime(int x) {
std::cout << "Calculating. Please, wait...\\n";
for (int i = 2; i < x; ++i) if (x % i == 0) return false;
return true;
}
int main() {
// call is_prime(313222313) asynchronously:
std::future<bool> fut = std::async(is_prime, 313222313);
std::cout << "Checking whether 313222313 is prime.\\n";
bool ret = fut.get();// waits for is_prime to return
if (ret)
std::cout << "It is prime!\\n";
else
std::cout << "It is not prime.\\n";
return 0;
}
【前两行可能顺序不同,或者乱序】
Checking whether 313222313 is prime.
Calculating. Please, wait...
It is prime!【大约1.5秒后】
std::async会首先创建线程执行is_prime(313222313), 任务创建之后std::async立即返回一个std::future对象。
主线程可使用std::future::get
获取结果,如果调用过程中,任务尚未完成,则主线程阻塞至任务完成。
主线程也可使用std::future::wait_for
等待结果返回,wait_for可设置超时时间,如果在超时时间之内任务完成,则返回std::future_status::ready
状态;如果在超时时间之内任务尚未完成,则返回std::future_status::timeout
状态。
#include <future>
#include <iostream>
bool is_prime(int x) {
for (int i = 2; i < x; ++i) if (x % i == 0) return false;
return true;
}
int main() {
std::future<bool> fut = std::async(is_prime, 700020007);
std::cout << "please wait";
std::chrono::milliseconds span(100);
while (fut.wait_for(span) != std::future_status::ready)
std::cout << ".";
std::cout << std::endl;
bool ret = fut.get();
std::cout << "final result: " << ret << std::endl;
return 0;
}
please wait.......................【please wait立即打印,然后每100ms打印一个“.”】
final result: 1【上面“.”全部出现后】
while()判断std::future_status状态,等待100ms后,发现is_prime未执行完,打印“.”号,然后再等待100ms,直到是ready状态,说明is_prime执行完毕。然后执行main()里余下的语句。
以上是关于cpp►C++11标准线程库<thread>的主要内容,如果未能解决你的问题,请参考以下文章
python opencv error “parallel_impl.cpp (240) WorkerThread 155: Can‘t spawn new thread: res = 11“(代码片