文章目录
- 一、主线程阻塞等待子线程返回
- 1、代码示例
- 2、代码改进
一、主线程阻塞等待子线程返回
主线程等待一个线程,此线程会开始连接一个服务器并循环读取服务器存储的值,主线程会阻塞直到连接服务器成功。因为如果不阻塞,可能上层业务刚开始读不到数据。
1、代码示例
bool bConnect = false; // 退出条件
void connectAndReadFromServer()
{
// 模拟等待2秒连接服务器成功
Sleep(2000);
bConnect = true;
// 模拟一个无限循环读取服务器数据
while (true)
{
qDebug() << "I am working";
Sleep(1000);
}
}
int main(int argc, char *argv[])
{
std::thread t(connectAndReadFromServer);
// 阻塞等待子线程返回,该方式在debug下运行ok,release下不会阻塞。
while (!bConnect)
{
}
qDebug() << "main thread continue, start read " << bConnect;
return 0;
}
坑点:上述代码在debug下运行是没有问题的,因为编译器会关闭大部分优化,目的是保留代码的原始行为,方便调试。 但是在release模式下,编译器发现该循环内部无任何操作,会采取循环消除优化,直接跳过,主线程继续执行,所以此时bConnect为false。
2、代码改进
int num = 0;
while (!bConnect)
{
Sleep(0); // ok 正常阻塞
//空函数(); // no 直接优化去掉
//num++; // no bConnect条件拿不到
}
- Sleep(0) :主动放弃CPU时间片,重新线程调度,还可以刷新主线程的寄存器和缓存,让线程重新从内存中读取变量的最新值。
- 空函数() :在release下,该循环不执行,直接被编译器优化掉。
- 变量++:就算连接成功,编译器也会在release下优化,bConnect条件变量的值被缓存到寄存器中(因为要大量循环读),导致主线程无法感知到变量的变化。循环一直执行。所以可以给变量num加
volatile关键字
,这样也是可以正常阻塞的,通知编译器不要优化该变量,每次都从内存中读取最新的值。