如果调用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的原理及其应用场景。