试试下面这段代码的输出是什么?
#include
#include
#include
class foo
{
public:
foo()
{
printf( "before sleep\n" );
Sleep( 1000 );
printf( "after sleep\n" );
}
void test()
{
printf( "in test\n" );
}
};
foo* bar()
{
static foo a;
return &a;
}
unsigned __stdcall thread( void* )
{
foo* p = bar();
p->test();
return 0;
}
int _cdecl main( int argc, char** argv )
{
for( int i = 0; i < 10; ++i )
{
uintptr_t t = _beginthreadex( NULL, 0, thread, NULL, 0, NULL );
CloseHandle( (HANDLE)t );
}
Sleep( 5000 );
return 0;
}
不知道C/C++标准有什么规定没有, 但粗看起来好像是编译器的问题呀。我用的是vc8,谁帮忙测测别的编译器。
根据星星的建议,把输出贴出来,如下:
before sleep
in test
in test
in test
in test
in test
in test
in test
in test
in test
after sleep
in test
这里的问题是至少有10个中的9个线程没有等对象初始化完成,就已经调用对象的方法了,这肯定是不对的。我大概看了一下反汇编的结果,实际上还可能出现构造函数被调用多次的情况。
要解决这个问题,在编译器的层次上要容易一点。如果是在用户程序的层次上,则麻烦的多,因为这类方法都会涉及到另一个静态变量的初始化。
posted on 2008-05-29 09:33 局部变量 阅读(2077)
re: 多线程和函数里的静态变量
2008-05-29 17:46
因为多线程你莫有同步。。。
class CCriticalSection
{
public:
CCriticalSection() { ::InitializeCriticalSection( &m_cs ); }
~CCriticalSection() { ::DeleteCriticalSection( &m_cs ); }
void Lock() { ::EnterCriticalSection( &m_cs ); }
void Unlock() { ::LeaveCriticalSection( &m_cs ); }
private:
CRITICAL_SECTION m_cs;
};
CCriticalSection cs;
class foo
{
public:
foo()
{
printf( "before sleep\n" );
Sleep( 3000 );
printf( "after sleep\n" );
}
void test()
{
printf( "in test\n" );
}
};
foo* bar()
{
cs.Lock();
static foo a;
cs.Unlock();
return &a;
}
unsigned __stdcall thread( void* )
{
foo* p = bar();
p->test();
return 0;
}
int _cdecl main( int argc, char** argv )
{
for( int i = 0; i {
uintptr_t t = _beginthreadex( NULL, 0, thread, NULL, 0, NULL );
CloseHandle( (HANDLE)t );
}
Sleep( 5000 );
return 0;
}
re: 多线程和函数里的静态变量
2008-05-29 17:49
锁是放在 bar() 中好?还是 thread() 中好?
to bl: 你的方法是错的
2008-05-29 20:01
我在最后已经说了“
如果是在用户程序的层次上,则麻烦的多,因为这类方法都会涉及到另一个静态变量的初始化” 。所以常见的多线程同步方式在这里都会失效。
你的问题是无法保证临界区先于对象初始化,虽然也许在这个例子中确实是它先初始化的。
re: 多线程和函数里的静态变量
2008-05-29 21:15
倒。。。....那临界区先于线程就可以了。。。
re: 多线程和函数里的静态变量
2008-05-29 21:23
这个例子很好的说明了,这种形式的单件的缺点就是构造的时候线程不安全
to heroboy
2008-05-30 09:02
握手, 这个例子正是我在考虑单件的问题时想到的, 其实单件还有几个其它问题, 打算过几天全写出来。
to 玻璃小屋:
“临界区先于线程就可以了”,在这个例子中是这样。但在实际项目中只保证这一点是不够的,必须保证临界区先于对象, 否则就可能在临界区初始化之前Enter它了。
据我所知,用户程序中要保证临界区先初始化,只能靠#pragma init_seg,但我想多数C++程序员根本不知道这个选项
re: 多线程和函数里的静态变量
2008-05-30 10:41
其实,构造函数到汇编这层后 就是一普通函数,他有可能被不同线程执行。。。 而所谓的单件 就是一全局部变量~ 临界区也是全局的~ 全局的东西被构造出来之后,才能轮到 程序执行。。也就是线程执行。。。
所以说。。我认为你这样还是 对 全局部变量 进行多线程访问同步控制的问题 -.-!
re: 多线程和静态变量
2008-06-03 11:58
我觉得输出很正常啊,甚至输出乱码都有可能。
函数里的static 变量,在函数第一次调用时初始化,程序退出时析构(函数间的内部static变量析构顺序是不确定的)。
re: 多线程和静态变量
2008-06-03 12:03
不好意思,明白你的意思了。不过,我觉得编译器视乎也很难对你的static foo a;进行保护,他未必知道你要多线程使用bar函数。他要是随便多线程保护掉,那么性能上会有损失。最关键的是,这本来是用户层是否多线程事,编译器来做似乎不太合理。
to 清风雨
2008-06-03 13:40
对于vc来说,如果我用多线程运行时库, 它就应该保护。否则可以不保护。我想到了一种实现方法,代价根本不高.
re: 多线程和函数里的静态变量
2008-06-04 22:15
代价不高,也是有代价的。不符合C++的精神:你不需要为你不使用的东西付出代价。
这个例子,直接在线程启动前调用一下bar(),就什么问题都解决了,也不需要什么同步了
to 小明
2008-06-05 08:39
你的做法恰恰违反了c++的精神, 如果程序的某次运行根本不需要调用bar(),那我的做法没有为不使用的东西付出代价,而你的付出了.
re: 多线程和函数里的静态变量
2008-06-05 12:20
C++ 只是编译器的C++。。。运行期没有C++ 只有面向过程。。。
to boli
2008-06-05 12:50
刚才讨论的已经超出语言的范畴了:)
不过小明的另外一个问题是:不付出代价是有前提的,这个前提是“正确”,错误的做法再“廉价”也没有用
re: 多线程和函数里的静态变量
2008-06-05 17:54
靠,都説些啥啊,静态变量本身都只初始化一次,还扯出多线程的问题!郁闷!
re: 多线程和函数里的静态变量
2008-06-06 16:08
ls,多线程的问题会造成静态变量被初始化多次的。
--------------------next---------------------