当一个线程在运行时,该线程有可能会停止一段时间,然后再继续运行。这就是所谓的睡眠。程序员必须决定一个线程是否需要睡眠。如果线程必须睡觉,程序员必须决定线程何时何地(在语句序列的哪个位置)必须睡觉。
下一个问题是,"什么是线程?"一个线程就像C++程序中的一个子程序。一个普通的简单C++程序就像一个线程。实际上,main()函数才是一个线程。main()函数是一个顶层函数。一个C++程序可以有其他顶层函数。其他每个顶层函数都可以正式转换成一个线程。C++的main()函数的行为就像一个线程,不需要任何形式上的转换(变成一个线程)。
C++标准命名空间有一个类似静态的类,this_thread。这个静态类有以下成员函数。
void sleep_for(rel_time)
和
void sleep_until(abs_time)
这些以 "this_thread:: "开头的函数可以在任何线程中使用,包括main()函数。main()函数不需要向线程进行任何转换。这些函数中的每一个都可以用来让一个线程休眠。这些函数中的每一个都需要一个参数。然而,参数的类型是不同的。
sleep_for()使用相对时间作为参数,而sleep_until()使用绝对时间作为参数。 rel_time,意思是相对时间,是线程睡眠的时间。另一方面,用abs_time,意思是绝对时间,对于函数sleep_until(),abs_time是线程将从睡眠中醒来的时间点。在这种情况下,当sleep_until()函数被执行时,线程开始睡觉。
C++中的Time_point是UNIX纪元之后的时间点。UNIX的纪元是1970年1月1日。
这篇文章解释了如何让线程睡觉。它首先总结了如何对线程进行编码。它还解释了如何在C++中制作一个简单的程序,sleep。
文章内容
线程编码总结
下面的程序有两个线程:其中一个是main()函数,另一个是,thread。
#include <iostream>
#include <thread>
using namespace std;
void funct() {
cout <<"Code A goes here." <<endl;
cout <<"Code B goes here." <<endl;
}
int main()
{
thread thr(funct);
thr.join();
return 0;
}
输出的结果是:
Code A goes here.
Code B goes here.
该程序开始时包含了iostream库。接下来,是加入线程库,这是必须的。之后的一行是一个声明。这个声明确保程序中在它下面使用的任何名称都是标准名称空间的,除非另有说明。然后是顶级函数的定义,funct()。
在这个定义之后是main()函数。main()函数也是一个函数定义。main()函数中的第一条语句是实例化线程,thr。thr的参数是顶层函数的名称,funct()。在这个实例化中,函数funct()被调用。有效的线程是顶层函数。注意,main()函数和线程一样,没有任何关于线程的正式声明,但函数funct()有。
main()函数中的下一条语句是join()语句。这条语句必须在调用线程的函数体中出现。如果没有这条语句,main()线程可能会运行到完成,而线程本身没有完成。事实上,如果没有这条语句,g++编译器将不会编译该程序,它将发出错误信息。
相对和绝对时间对象
持续时间,间隔时间
sleep_for()函数接受一个持续时间对象作为参数。这就是相对时间。在加入chrono库后,可以按以下方式创建相对时间对象。
chrono::hours hs(3);
chrono::minutes ms(3);
chrono::seconds ss(3);
chrono::milliseconds mss(3);
chrono::microseconds miss(3);
这里有3个小时,名称为hs;3分钟,名称为ms;3秒,名称为ss;3毫秒,名称为mss;3微秒,名称为miss。
1毫秒=1/1000秒。1微秒=1/1000000秒。
时间点
C++中的时间点(Time_point),是指UNIX纪元之后的时间点。UNIX的纪元是1970年1月1日。这就是绝对时间。函数sleep_until()使用绝对时间对象作为其参数。随着Chrono库的加入,绝对时间对象,在现在之后,可以按以下方式创建。
chrono::system_clock::time_point tp = chrono::system_clock::now() + chrono::hours(3);
chrono::system_clock::time_point tp = chrono::system_clock::now() + chrono::minutes(3);
chrono::system_clock::time_point tp = chrono::system_clock::now() + chrono::seconds(3);
chrono::system_clock::time_point tp = chrono::system_clock::now() + chrono::milliseconds(3);
chrono::system_clock::time_point tp = chrono::system_clock::now() + chrono::microseconds(3);
这些对象的名称都是tp。
按相对时间睡眠
主要功能
要通过相对时间或持续时间进行睡眠,必须使用sleep_for()函数,前面加上 "this_thread::"。持续时间从该函数被执行时开始。main()函数是主线程,它不需要任何声明。在下面的程序中,main函数睡眠时间为1秒。
#include <iostream>
#include <thread>
#include <chrono>
using namespace std;
int main()
{
cout <<"Code A goes here." <<endl;
chrono::seconds ss(1);
this_thread::sleep_for(ss);
cout <<"Code B goes here." <<endl;
return 0;
}
输出结果是:
Code A goes here.
并在一秒钟后。
Code B goes here.
被显示出来。这个单线程程序没有线程声明;因为线程是main()函数。请注意,Chrono库和线程库都被包含在内。
主函数的输出是两个字符串。在这两个字符串之间,有一段代码。
chrono::seconds ss(1);
this_thread::sleep_for(ss);
注意睡眠函数是如何被使用的。
常规线程
对传统线程的解释,与上面的解释相似,但计时代码是在实际的线程体中。在下面的程序中,线程睡眠时间为1秒。
#include <iostream>
#include <thread>
#include <chrono>
using namespace std;
void funct() {
cout <<"Code A goes here." <<endl;
chrono::seconds ss(1);
this_thread::sleep_for(ss);
cout <<"Code B goes here." <<endl;
}
int main()
{
thread thr(funct);
thr.join();
return 0;
}
输出结果是:
Code A goes here.
并在一秒钟后。
Code B goes here.
被显示出来。这里有两个线程:常规线程和main()函数。请注意,Chrono库和线程库都被包含在内。
在常规线程的函数主体中,有两个字符串。在这些字符串之间,有这样的代码。
chrono::seconds ss(1);
this_thread::sleep_for(ss);
注意这两条语句之间的关系。
按绝对时间睡眠
要通过绝对时间睡眠,必须使用sleep_until()函数,前面加上 "this_thread::" 。时间从UNIX纪元开始到未来的某个时间。如果绝对值或时间点参数是在过去,那么它将被忽略。所以,线程实际上应该在未来的时间点上被唤醒。
主函数
main()函数是主线程,它不需要任何声明。在下面的程序中,main函数睡眠到现在后1秒,时间从1970年1月1日(UNIX纪元)开始。
#include <iostream>
#include <thread>
#include <chrono>
using namespace std;
int main()
{
cout <<"Code A goes here." <<endl;
chrono::system_clock::time_point tp = chrono::system_clock::now() + chrono::seconds(1);
this_thread::sleep_until(tp);
cout <<"Code B goes here." <<endl;
return 0;
}
输出的结果是:
Code A goes here.
并在一秒钟后。
Code B goes here.
被显示出来。这是一个单线程程序,没有线程声明;因为线程是main()函数。请注意,Chrono库和线程库都被包含在内。
在main函数中输出了两个字符串。在这两个字符串之间,有一段代码。
chrono::system_clock::time_point tp = chrono::system_clock::now() + chrono::seconds(1);
this_thread::sleep_until(tp);
注意睡眠函数是如何被使用的
常规线程
对传统线程的解释与上面的解释相似,但计时代码在实际的线程体中。在下面的程序中,线程一直睡到现在的1秒之后。
#include <iostream>
#include <thread>
#include <chrono>
using namespace std;
void funct() {
cout << "Code A goes here." <<endl;
chrono::system_clock::time_point tp = chrono::system_clock::now() + chrono::seconds(1);
this_thread::sleep_until(tp);
cout << "Code B goes here." <<endl;
}
int main()
{
thread thr(funct);
thr.join();
return 0;
}
输出结果是:
Code A goes here.
并在一秒钟后。
Code B goes here.
被显示出来。这里有两个线程:常规线程和main()函数。请注意,Chrono库和线程库都被包含在内。
在常规线程的函数主体中,输出了两个字符串。在这些字符串之间,有这样的代码。
chrono::system_clock::time_point tp = chrono::system_clock::now() + chrono::seconds(1);
this_thread::sleep_until(tp);
注意这两条语句之间的关系。
结论
可以让一个线程在某个时间段内睡眠,或者在UNIX纪元后的某个时间段内睡眠并唤醒。要想让线程在某个时间段内睡觉,可以使用sleep_for()函数。要想睡觉并唤醒,请使用sleep_until()函数。这些函数中的每一个都必须在前面加上这个,"this_thread::"。一个正常的简单C++程序是一个线程程序。这里的线程是main()函数,不需要线程声明。