大家好,最近我在工作当中遇到了一个函数,就是c++中的sleep_for函数,说实话,这还真是我第一次见到这个函数,所以我就花了点时间研究了一下这个函数,现在想总结一下分享给大家。
一、sleep_for函数的简介
二、sleep_for函数用到的情景
三、sleep_for函数,sleep函数以及yield函数三者的区别
四、关于c++中chrono函数的使用
五、关于c++中时间的获取方法
一、sleep_for函数的简介
先简单说一下sleep_for这个函数的情况。
1、这个函数是一个线程函数,换句话说他的作用域只作用于当前线程,因此,包含它的库也就是thread库。
2、这个函数的原型为
sleep_for(const chrono::duration<_Rep, _Period>& __rtime)(关于chrono的部分我们待会再说,我们只要知道这是个时间间隔)
3、这个函数要实现的目的就是线程阻塞,换句话说就是要让当前的线程休眠一段时间(具体时间就是我们传进去的参数),而其他进程不休息。
最后举一个使用例子:std::this_thread::sleep_for(std::chrono::miliseconds(50)) //表示让该线程休眠50ms
二、sleep_for用到的场景
这里说一下我们为什么要用sleep_for,是这样的,我们这个代码中要发给底层硬件发送一条指令,我们知道硬件的处理速度是有一定时间的,所以为了不影响后续的代码的运行,所以需要
做一个线程阻塞,保证其在这段时间内硬件处理完毕。
三、关于sleep_for,sleep以及yield函数三者的区别
关于sleep_for,它还有一个类似的函数,叫yield,他的作用域,参数和sleep_for是一样的,它的函数原型是这样的:
std::this_thread::yield: 当前线程放弃执行,操作系统调度另一线程继续执行。即当前线程将未使用完的“CPU时间片”让给其他线程使用,等其他线程使用完后再与其他线程一起竞争"CPU"。
另外我们在系统中还有一个阻塞函数sleep函数,所以我们说一说三者的区别。
我们先来说sleep函数,我们有两点要说明:
1、sleep函数是系统函数,换句话说它不需要c++11支持,只要有编译器就能找到这个函数。
2、sleep函数是进程阻塞函数,换句话说一旦调用这个函数,当前进程当中所有的线程全部阻塞。
接着我们说其他两个函数:我们来看一下代码:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
int n=0;
std::thread t1(function1, std::ref(n));
std::thread t2(function2, n);
t1.join();
t2.join();
w.show();
return a.exec();
}
void function1(int &n)
{
while (true) {
std::this_thread::sleep_for(std::chrono::seconds(1));
n++;
if (n==10) {
mux.lock();
g_flag = true;
mux.unlock();
} else if(n == 15) {
mux.lock();
// std::this_thread::sleep_for(std::chrono::seconds(5));
mux.unlock();
}
else if (n == 20) {
mux.lock();
g_flag = false;
mux.unlock();
} else if (n == 30) {
mux.lock();
g_flag = true;
mux.unlock();
}
else {
std::cout<<"F1 is:"<<n<<std::endl;
}
}
}
void function2(int n)
{
while(true) {
std::this_thread::sleep_for(std::chrono::seconds(1));
// std::this_thread::yield();
n++;
std::cout<<"F2 n: "<<n<<std::endl;
mux.lock();
bool flag = g_flag;
mux.unlock();
if (flag) {
} else {
}
}
}
这里有两个线程,依次打印n的值,我们首先是不加yield语句打出来的结果
看到了吗?两个函数的执行过程是随机的,这是因为CPU时间片调度算法本身就是随机的。
接下来我们看一下加上yield的效果。
这个效果是是什么呢?F1永远在F2前面,另外,F2中的n也在不断增长
好了,到这里我们可以总结一下yield函数了,这个函数要注意两点:
1、std::this_thread::yield(); 是将当前线程所抢到的CPU”时间片A”让渡给其他线程(其他线程会争抢”时间片A”,
等到其他线程使用完”时间片A”后, 再由操作系统调度, 当前线程再和其他线程一起开始抢CPU时间片.
就是说第一,遇到这个函数会优先让其他线程执行,第二,其他线程执行完我还是会执行的。
四、关于c++中chrono函数的使用
这个库是c++11定义出来的关于处理时间的库,有了它处理时间问题就会非常方便了。我们在这里简单介绍一下这个库的一些常用方法。
1、duration_cast(这个主要实现的功能就是可以将单位进行转换,比如说我们获取到的系统时间可能是毫秒,但是我们要把他换算成秒怎么办,就用这个)。
2、system_clock::now(这个函数的主要目的就是获取到当前系统时间,注意这个时间是当前时间与1970年1月1之间的差值,单位是time_point)
3、time_since_porch (这个函数也是当前时间与1970年1月1日之间的差值,单位是duration)
4、localtime(间隔)(这个函数可以将当前时间与1970年的差值,转换成包含今天年月日的结构体,不过注意,传进去的一定是秒)
5、strftime函数(这个函数可以将结构体指针转换成包含时间格式的字符串数组)
6、to_time_t(将timepoint时间转换成time_t)
五、时间函数
首先我们说一下,时间到底有啥用,其实我想了想,其用途无非就是两点,第一获取到当前的年月日时分秒,第二就是计算两段代码相隔的时间。所以我就着重说这两部分。
1、获取到当前时间的年月日
无论是什么函数,他的流程一定是这样的。获取到time_point值,然后获取到tm的值,最后获取到年月日时分秒。
1、先说第一种方法
auto now = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count(); //获取到time_point的值并将其转换成秒
ts = localtime(&now) //获取到当前的tm值
int year = ts.tm_year + 1900;
int month = ts.tm_mon + 1;
int day = ts.tm_mday;
int hour = ts.tm_hour;
int minute = ts.tm_min;
int second = ts.tm_sec;
获取到当前年月日时分秒的值
2、再说第二种方法
auto tn = std::chrono::system_clock::now(); // 获取到time_point
time_t now1 = std::chrono::system_clock::to_time_t(tn); // 获取time_t的值
ts = localtime(&now); // 获取tm的值
const char *fmt = "%Y-%m-%d %H:%M:%S";
strftime(buf, sizeof(buf), fmt, ts); // 将其转换成字符串的形式
2、获取到当前程序运行的时间
auto t0 = std::chrono::system_clock::now();
j++;
auto time2 = std::chrono::system_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::nanoseconds>
(std::chrono::system_clock::now() - t0).count()<<std::endl;
通过得到时间戳相减得到最终的值,另外我测的话一行代码时间58ns,所以只好设置na秒级别了。
这就是通过sleep_for函数引发的思考。