生成单个可执行线程,可以在多线程环境中与其他线程并发执行,同时共享相同的地址空间。初始化的线程对象拥有唯一的线程id,状态为joinable;未初始化的线程对象状态为non-joinabe,与其他non-joinable的线程对象共用通用的线程id。线程对象从joinable到non-joinable有以下两种途径:1)通过move被转移; 2)线程调用join或者detach函数。
(1). 默认构造,创建一个空的thread对象,状态non-joinable。
(2). 初始化构造,传递功能函数fn和参数args,状态joinable。创建成功线程立即启动。
(3). 拷贝构造函数(被禁用),意味着 thread 不可被拷贝构造。
(4). 移动构造,传递线程x的句柄。构造成功后x置空,等同于(1)。
注意:处于joinable状态的线程对象必须调用join或者detach函数后才能被销毁。
//参数传递
#include
using namespace std;
void fun1(int n)
{
//do something...
}
void fun2(int & n)
{
//do something...
}
int main()
{
int n = 0;
thread t1; //默认构造
thread t2(fun1, n); //初始化构造(值传递)
t2.join();
n = 10;
thread t3(fun2, ref(n)); //初始化构造(引用传递)
thread t4(move(t3)); //移动构造(t4是执行线程,t3变空线程,等同于t1)
t4.join();
return 0;
}
bool joinable() const noexcept; // 判断线程对象是否joinable
joinable:
non-joinable:
无论在windows中还是Posix中,主线程和子线程的默认关系是:无论子线程执行完毕与否,一旦主线程执行完毕退出,所有子线程执行都会终止。这时整个进程结束或僵死,部分线程保持一种终止执行但还未销毁的状态,而进程必须在其所有线程销毁后销毁,这时进程处于僵死状态。线程函数执行完毕退出,或以其他非常方式终止,线程进入终止态,但是为线程分配的系统资源不一定释放,可能在系统重启之前,一直都不能释放,终止态的线程,仍旧作为一个线程实体存在于操作系统中,什么时候销毁,取决于线程属性。在这种情况下,主线程和子线程通常定义以下两种关系:
1、可会合(joinable):这种关系下,主线程需要明确执行等待操作,在子线程结束后,主线程的等待操作执行完毕,子线程和主线程会合,这时主线程继续执行等待操作之后的下一步操作。主线程必须会合可会合的子线程。在主线程的线程函数内部调用子线程对象的wait函数实现,即使子线程能够在主线程之前执行完毕,进入终止态,也必须执行会合操作,否则,系统永远不会主动销毁线程,分配给该线程的系统资源也永远不会释放。
2、相分离(detached):表示子线程无需和主线程会合,也就是相分离的,这种情况下,子线程一旦进入终止状态,系统立即销毁线程,回收资源。这种方式常用在线程数较多的情况下,有时让主线程逐个等待子线程结束,或者让主线程安排每个子线程结束的等待顺序,是很困难或不可能的,所以在并发子线程较多的情况下,这种方式也会经常使用。
在任何一个时间点上,线程是可结合(joinable)或者是可分离的(detached),一个可结合的线程能够被其他线程回收资源和杀死,在被其他线程回收之前,它的存储器资源如栈,是不释放的,相反,一个分离的线程是不能被其他线程回收或杀死的,它的存储器资源在它终止时由系统自动释放。
线程的分离状态决定一个线程以什么样的方式来终止自己,在默认的情况下,线程是非分离状态的,这种情况下,原有的线程等待创建的线程结束,只有当pthread_join函数返回时,创建的线程才算终止,释放自己占用的系统资源,而分离线程没有被其他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源。
(1). 如果线程对象现在是non-joinable,则其获取由右值引用(rhs)表示的执行线程。如果是joinable,则调用terminate(),默认终止线程。右值传递之后,不再表示任何执行线程。
(2). 线程对象无法被复制(线程对象是可转移的,不可复制的)
// example for thread::operator=
#include // std::cout
#include // std::thread, std::this_thread::sleep_for
#include // 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::thread threads[5]; // default-constructed threads
std::cout << "Spawning 5 threads...\n";
for (int i=0; i<5; ++i)
threads[i] = std::thread(pause_thread,i+1); // move-assign threads
std::cout << "Done spawning threads. Now waiting for them to join:\n";
for (int i=0; i<5; ++i)
threads[i].join();
std::cout << "All threads joined!\n";
return 0;
}
void join(); //将子线程加入汇合队列
void detach(); //分离线程
detach与join最大的区别在于:线程调用join后被阻塞,等到子线程运行完毕汇合后再继续后续操作,最后一起释放资源。detach不需要阻塞和汇合,调用线程和子线程完全分离,资源独立释放,可能出现调用线程结束了子线程还在后台运行的情况。
id get_id() const noexcept; //获取线程id
native_handle_type native_handle(); //返回当前线程句柄
void swap (thread& x) noexcept; //交换两个线程的状态信息,比如线程id
void swap (thread& x, thread& y) noexcept; //交换线程x和y的状态
//该方法是函数swap的重载,效果类似于x.swap(y)。
static unsigned hardware_concurrency() noexcept; //返回硬件线程上下文数量
此处并非返回系统可用处理器或者内核的实际数量,因为每个处理单元可以支持多个线程。只能返回一个硬件线程数量的近似值,如果该值无法计算或者没有很好地定义,则返回0.
thread::id get_id() noexcept; //返回当前线程的id号
template <class Rep, class Period>
void sleep_for (const chrono::duration<Rep,Period>& rel_time); //线程休眠一段时间
当前线程休眠rel_time长的时间,其他线程照常运行。示例:std::this_thread::sleep_for (std::chrono::seconds(1));
template <class Clock, class Duration>
void sleep_until (const chrono::time_point<Clock,Duration>& abs_time); //线程休眠到某个时间点
当前线程休眠到时间点abs_time,其他线程照常运行。示例:std::this_thread::sleep_until (system_clock::from_time_t (mktime(ptm)));
void yield() noexcept; //当前线程让步给其他线程执行
重新调度线程的实现,其他线程优先执行,当前线程等待(注意:此时未休眠)
// this_thread::yield example
#include // std::cout
#include // std::thread, std::this_thread::yield
#include // 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();
std::cout << '\n';
return 0;
}
输出:
race of 10 threads that count to 1 million...
6189370542