std::this_thread::yield解析

如果调用std::this_thread::yield函数,当前线程会马上让出当前的CPU时间片,由运行态变为就绪态,但只是说明该线程当前的这次调度运行结束了,该线程会和其他线程一起共同由操作系统调度运行,至于该线程下次什么时候被调度运行,完全取决于系统的调度算法,yield函数并不会影响操作系统对该线程的下一次调度。其实和return效果类似,都是退出,但是对于一个线程来说,在该线程的回调函数调用return函数就会返回,该线程就会结束,而yield并不会,正因为此,yield函数有着特殊的用途。

我们可以看下官方的实例:

#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();
 
    little_sleep(std::chrono::microseconds(100));
 
    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 100 microseconds

每一次线程调度,do while循环只会执行一次,就会让出,为了对比更明显,我们加一个变量来作比对,给出两份代码,首先看代码1:

#include <iostream>
#include <chrono>
#include <thread>
 
// "busy sleep" while suggesting that other threads run 
// for a small amount of time
int cnt = 0;
void little_sleep(std::chrono::microseconds us)
{
    auto start = std::chrono::high_resolution_clock::now();
    auto end = start + us;
    do {
	cnt ++;
        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 << "cnt val is " << cnt << std::endl;
}

运行结果:

cnt val is 30

代码2将yield去掉:

#include <iostream>
#include <chrono>
#include <thread>
 
// "busy sleep" while suggesting that other threads run 
// for a small amount of time
int cnt = 0;
void little_sleep(std::chrono::microseconds us)
{
    auto start = std::chrono::high_resolution_clock::now();
    auto end = start + us;
    do {
	cnt ++;
    } 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 << "cnt val is " << cnt << std::endl;
}

运行结果如下:

cnt val is 866

可以看到,由于yied函数导致每次调用while循环只会执行一次,因此该线程占用时间片大大减少。那么这有什么用呢?设想这样一个线程,其对应的回调函数内部代码为:

while(!event) {
}
call_func();

也就是该线程会一直检测event是否发生,只有发生了while循环才会退出执行下面的call_func,如果不加yield就会占用过多的资源,而使用std::slepp_for()又可能造成延时过长,所以使用yield,每次调用只作一次检测,既降低了线程的资源占用,又保证了延时不会过长(需要注意,与不加yield相比,由于时间片减少很多,延时肯定是会有增加的)。

while(!event) {
   std::this_thread::yield();
}
call_func();

因此我们有时候称此方法为busy_sleep,这就是yield的原理及其应用场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值