我有一个简单的代码片段,其中编译器优化了变量"done">
#include <pthread.h>
#include <stdbool.h>
bool done = false;
void *func(void *args)
{
done = true;
return NULL;
}
main()
{
pthread_t p1;
pthread_create(&p1, NULL, func, NULL);
printf("waitingn");
while(!done)
{}
printf("moving on...n");
}
在这里,如果没有volatile关键字,变量"done"被优化掉并进入无限循环。
我正在编译使用:
gcc -O2 volatile.c -lpthread
但是当我使用简单的func()版本:
#include <stdbool.h>
bool done = false;
void func()
{
done = true;
}
main()
{
func();
printf("waitingn");
while(!done)
{}
printf("moving on...n");
}
但是这里变量"done"没有优化出来,两者有什么区别?
编译器在第二种情况下猜出了"done"会改变一些方式,但不是在Pthread的情况下?
我的GCC版本是:
gcc -版本gcc (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609
在这两种情况下,变量done
都没有优化出来。优化出来的(在这两种情况下)是while循环中done
的read。这个读操作被提升到循环之外,在循环之前发生一次;然后循环运行0次或无限次,这取决于在循环之前读取的done
的值。它实际上变成了
if (!done)
while (true) {}
else
while (false) {}
,然后进一步简化为
if (!done) while (true) {}
建议代码如下:
- 包含丢失的头文件:'stdio.h'用于'printf()'和'fprintf()'
- 正确退出线程函数
- 正确地使'主线程'等待子线程以避免"燃烧所有可用的CPU周期">
- 正确检查调用'pthread_create()'的状态——这个函数不设置'errno'
- 正确处理'args'参数以避免编译器警告
- 消除'无用'变量'done'
- 为'main()'使用有效签名
- 包含适当的水平间距以提高可读性
- 删除不需要的标头' stdbook .h'
现在,建议的代码:
#include <pthread.h>
#include <stdio.h> // printf(), fprintf()
#include <stdlib.h> // exit() and EXIT_FAILURE
//bool done = false;
void *func( void *args )
{
(void)args; // eliminate warning about unused argument
//done = true;
//return NULL;
pthread_exit( NULL );
}
int main( void ) //use valid signature for 'main()'
{
pthread_t p1;
if( pthread_create( &p1, NULL, func, NULL ) != 0 )
{
fprintf( stderr, "call to pthread_create() failedn" );
exit( EXIT_FAILURE );
}
printf( "waitingn" );
pthread_join( p1, NULL ); // wait for sub thread to exit
//while(!done)
//{}
printf( "moving on...n" );
}