考慮一下多線程代碼,在設計上,App為了擷取更多的功能,從Window派生,而App同時為了擷取
某個子產品的回調(所謂的Listener),App同時派生Listener,并将自己的指針交給另一個子產品,
另一個子產品通過該指針多态回調到App的實作(對Listener規定的接口的implemention)。設計上
隻是一個很簡單的Listener回調,在單線程模式下一切都很正常(後面我會羅列代碼),但是換到
多線程下,編譯器似乎就對語言機制的支援不夠了:
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? ///
多線程下vc2003,vc2005對虛函數表處理的BUG? /// to demonstrate the fucking bug.
多線程下vc2003,vc2005對虛函數表處理的BUG? ///
多線程下vc2003,vc2005對虛函數表處理的BUG? #include < iostream >
多線程下vc2003,vc2005對虛函數表處理的BUG? #include < process.h >
多線程下vc2003,vc2005對虛函數表處理的BUG? #include < windows.h >
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? class Window
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? {
多線程下vc2003,vc2005對虛函數表處理的BUG? public:
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? ///
多線程下vc2003,vc2005對虛函數表處理的BUG? virtual void wrong()
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? {
多線程下vc2003,vc2005對虛函數表處理的BUG? std::cout << "wrong" << std::endl;
多線程下vc2003,vc2005對虛函數表處理的BUG? }
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? virtual ~Window()
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? {
多線程下vc2003,vc2005對虛函數表處理的BUG? std::cout << "~Window" << std::endl;
多線程下vc2003,vc2005對虛函數表處理的BUG? }
多線程下vc2003,vc2005對虛函數表處理的BUG? } ;
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? class Listener
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? {
多線程下vc2003,vc2005對虛函數表處理的BUG? public:
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? /// as most listener class, it only put some interface here
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? virtual void show()
多線程下vc2003,vc2005對虛函數表處理的BUG? {}
多線程下vc2003,vc2005對虛函數表處理的BUG? } ;
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? class Game
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? {
多線程下vc2003,vc2005對虛函數表處理的BUG? public:
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? Game() : _listener( 0 )
多線程下vc2003,vc2005對虛函數表處理的BUG? { }
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? void init( Listener *listener )
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? {
多線程下vc2003,vc2005對虛函數表處理的BUG? _listener = listener;
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? /// it will call Window::wrong function but not App::show.
多線程下vc2003,vc2005對虛函數表處理的BUG? _listener->show();
多線程下vc2003,vc2005對虛函數表處理的BUG? }
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? private:
多線程下vc2003,vc2005對虛函數表處理的BUG? Listener *_listener;
多線程下vc2003,vc2005對虛函數表處理的BUG? } ;
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? Game gGame;
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? static unsigned int __stdcall ThreadFunc( void * p )
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? {
多線程下vc2003,vc2005對虛函數表處理的BUG? Listener *listener = (Listener*) p;
多線程下vc2003,vc2005對虛函數表處理的BUG? gGame.init( listener );
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? while( true )
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? {
多線程下vc2003,vc2005對虛函數表處理的BUG? std::cout << ".";
多線程下vc2003,vc2005對虛函數表處理的BUG? Sleep( 100 );
多線程下vc2003,vc2005對虛函數表處理的BUG? }
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? _endthreadex( 0 );
多線程下vc2003,vc2005對虛函數表處理的BUG? return 0;
多線程下vc2003,vc2005對虛函數表處理的BUG? }
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? class App : public Window, public Listener
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? {
多線程下vc2003,vc2005對虛函數表處理的BUG? public:
多線程下vc2003,vc2005對虛函數表處理的BUG? void init()
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? {
多線程下vc2003,vc2005對虛函數表處理的BUG? // create the game thread
多線程下vc2003,vc2005對虛函數表處理的BUG? _game_thread = (HANDLE)_beginthreadex( NULL, 0, ThreadFunc, this, 0, NULL );
多線程下vc2003,vc2005對虛函數表處理的BUG? }
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? /// implement the interface
多線程下vc2003,vc2005對虛函數表處理的BUG? void show()
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? {
多線程下vc2003,vc2005對虛函數表處理的BUG? std::cout << "App::show" << std::endl;
多線程下vc2003,vc2005對虛函數表處理的BUG? }
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? /// exit
多線程下vc2003,vc2005對虛函數表處理的BUG? void exit()
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? {
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? /// just for testing purpose
多線程下vc2003,vc2005對虛函數表處理的BUG? ::TerminateThread( _game_thread, 1 );
多線程下vc2003,vc2005對虛函數表處理的BUG? ::CloseHandle( _game_thread );
多線程下vc2003,vc2005對虛函數表處理的BUG? }
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? private:
多線程下vc2003,vc2005對虛函數表處理的BUG? HANDLE _game_thread;
多線程下vc2003,vc2005對虛函數表處理的BUG? } ;
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? App gApp;
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? int main()
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? {
多線程下vc2003,vc2005對虛函數表處理的BUG? gApp.init();
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? std::cout << "Press enter key to exit!" << std::endl;
多線程下vc2003,vc2005對虛函數表處理的BUG? std::cin.get();
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? gApp.exit();
多線程下vc2003,vc2005對虛函數表處理的BUG? return 0;
多線程下vc2003,vc2005對虛函數表處理的BUG? }
多線程下vc2003,vc2005對虛函數表處理的BUG? App多重繼承Window和Listener,在Game裡回調App::show時,卻調用到了Window::wrong函數。看上去,傳給
Game的Listener指針所指向的虛函數表錯誤了(vtable指針錯了)。App先繼承Listener後繼承Window時,情況
就正确了。(因為使用了_beginthreadex,程式需要連結多線程的運作時庫)
單線程情況下:
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? ///
多線程下vc2003,vc2005對虛函數表處理的BUG? ///
多線程下vc2003,vc2005對虛函數表處理的BUG? /// to demonstrate the fucking bug.
多線程下vc2003,vc2005對虛函數表處理的BUG? ///
多線程下vc2003,vc2005對虛函數表處理的BUG? /// OK, even it links the multi-thread crt.
多線程下vc2003,vc2005對虛函數表處理的BUG? #include < iostream >
多線程下vc2003,vc2005對虛函數表處理的BUG? #include " kl_thread.h "
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? class Window
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? {
多線程下vc2003,vc2005對虛函數表處理的BUG? public:
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? ///
多線程下vc2003,vc2005對虛函數表處理的BUG? virtual ~Window()
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? {
多線程下vc2003,vc2005對虛函數表處理的BUG? std::cout << "~Window" << std::endl;
多線程下vc2003,vc2005對虛函數表處理的BUG? }
多線程下vc2003,vc2005對虛函數表處理的BUG? } ;
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? class Listener
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? {
多線程下vc2003,vc2005對虛函數表處理的BUG? public:
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? /// as most listener class, it only put some interface here
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? virtual void show()
多線程下vc2003,vc2005對虛函數表處理的BUG? {}
多線程下vc2003,vc2005對虛函數表處理的BUG? } ;
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? ///
多線程下vc2003,vc2005對虛函數表處理的BUG? Listener * gListener;
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? class App : public Window, public Listener
多線程下vc2003,vc2005對虛函數表處理的BUG? // class App : public Listener, public Base
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? {
多線程下vc2003,vc2005對虛函數表處理的BUG? public:
多線程下vc2003,vc2005對虛函數表處理的BUG? void init()
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? {
多線程下vc2003,vc2005對虛函數表處理的BUG? gListener = this;
多線程下vc2003,vc2005對虛函數表處理的BUG? }
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? /// implement the interface
多線程下vc2003,vc2005對虛函數表處理的BUG? void show()
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? {
多線程下vc2003,vc2005對虛函數表處理的BUG? std::cout << "App::show" << std::endl;
多線程下vc2003,vc2005對虛函數表處理的BUG? }
多線程下vc2003,vc2005對虛函數表處理的BUG? } ;
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? App gApp;
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? int main()
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? {
多線程下vc2003,vc2005對虛函數表處理的BUG? gApp.init();
多線程下vc2003,vc2005對虛函數表處理的BUG?
多線程下vc2003,vc2005對虛函數表處理的BUG? gListener->show();
多線程下vc2003,vc2005對虛函數表處理的BUG? return 0;
多線程下vc2003,vc2005對虛函數表處理的BUG? }
多線程下vc2003,vc2005對虛函數表處理的BUG? 無論Listener, Window的順序如何,一切都很正常。這起碼說明了,在語言層次,我的做法是正确的。
而這個時候即使連結了多線程的運作時庫,結果也是正确的。
那麼錯誤可以歸結于多線程,可能是在多線程下編譯器對虛函數表初始化不正确所緻。這是否真的是
VC2003、VC2005的BUG?
posted on 2008-04-24 14:40 Kevin Lynx 閱讀(866) 評論(10) 編輯 收藏 引用 所屬分類: C++
多線程下vc2003,vc2005對虛函數表處理的BUG? <script type="text/javascript"> // </script>
評論
還是寫出來看的清楚:static unsigned int __stdcall ThreadFunc( void *p )
{
Listener *listener = (Listener*) p;
應該是
Listener *listener = (App*) p;
回複 更多評論
# re: 多線程下vc2003,vc2005對虛函數表處理的BUG? 2008-04-24 17:34 giscn
或者這樣
_game_thread = (HANDLE)_beginthreadex( NULL, 0, ThreadFunc, (Listener*)this, 0, NULL ); 回複 更多評論
# re: 多線程下vc2003,vc2005對虛函數表處理的BUG? 2008-04-24 17:40 giscn
錯誤由void* 指針轉換引起,與多線程無關,C++ 的指針轉換不同于C, 如果是多集繼承,參數同樣是 this, 其實際值不一定相同,取決于參數類型 回複 更多評論
# re: 多線程下vc2003,vc2005對虛函數表處理的BUG? 2008-04-24 17:40 eXile
樓上的正解。在使用多重繼承時要注意對象的布局。 回複 更多評論
# re: 多線程下vc2003,vc2005對虛函數表處理的BUG? 2008-04-24 18:09 亨德列克
Listener *listener = (Listener*) p; 是這一行錯了,這個錯誤應該很多人都會犯…… 回複 更多評論
# re: 多線程下vc2003,vc2005對虛函數表處理的BUG? 2008-04-24 19:18 Kevin Lynx
@亨德列克
不是那一行錯了,App和Game兩個類分屬不同子產品,為了不讓兩個子產品耦合,這裡使用Listener *listener = (Listener*) p,而不是(App*)p。
giscn和eXile (他删除了他的第二條評論:) )的方法是正确的。可以被采用,再次表示感謝。
這讓我意識到,void*在C++裡缺乏安全性。 回複 更多評論
# re: 多線程下vc2003,vc2005對虛函數表處理的BUG? 2008-04-24 22:49 飯中淹
這不是多線程的問題
當你先繼承window後繼承Listener的時候,App的記憶體結構如下:
class App
vt of Window
data of Window
vt of Listener
data of Listener
data of App
_beginthreadex的參數是void*,你把this傳遞進去,相當于傳遞CApp* this。其實隐含的就是Window*this,那麼裡面調用Listener->Show,自然就會去Window的vt裡面查找對應索引的函數,就會調用錯函數。
而第二個,因為你顯式的=this,是以,編譯器會進行轉換,進而把正确的Listener位址指派給那個全局指針,這時,無論繼承順序如何,都是正确的結果。
這其實是因為對象指針轉換不準确導緻的,不是vc的bug,也不是多線程的問題。
回複 更多評論
# re: 多線程下vc2003,vc2005對虛函數表處理的BUG? 2008-04-25 08:32 FongLuo
收藏,收藏,^_^ 回複 更多評論
# re: 多線程下vc2003,vc2005對虛函數表處理的BUG? 2008-04-25 17:03 #Ant
多繼承下還有這樣的問題,學習了。。。 回複 更多評論
# re: 多線程下vc2003,vc2005對虛函數表處理的BUG?[未登入] 2008-04-26 00:49 楊粼波
指針偏移,多線程會發生這樣滴問題。。。。
# re: 多線程下vc2003,vc2005對虛函數表處理的BUG? 2008-04-24 16:09 Fox