2011-03-05 52 views
1

我有一個類,我試圖轉換它的一些成員函數在不同的線程中運行。雖然該程序沒有問題,但它試圖從圖像緩衝區讀取(由不同的線程更新)時會崩潰。似乎問題是由_beginthread中的參數傳遞不正確引起的。類與多線程成員函數

下面的代碼片段應該更清楚地解釋我正在嘗試做什麼。基本上我試圖完成的是有成員函數「fillBuffer」填充圖像緩衝區,而其餘的程序正在做其他事情,包括同時讀取相同的圖像緩衝區。

任何有關該語法的幫助都將不勝感激。

const int MaxImgBufferSize = 5; 
     class MyFrame : public wxFrame 
     { 
     public: 
      // constructors 
      MyFrame(const wxString& title); 

     private: 
      static vector <IplImage*> ImgBuffer; 
      void changeWP(wxCommandEvent&); 
      void fillBuffer(); 
       void fillBufferFun(); 
       static void __cdecl getImgFromBuffer(void *); 
       static void __cdecl pushImgBuffer(void *); 
     }; 

    vector<IplImage*> MyFrame::ImgBuffer; 

     enter code here 

    MyFrame::MyFrame(const wxString& title) 
      : wxFrame(...) 
    { 
     // some stuff here 
     InitializeCriticalSection(&Section); 
     fillBuffer(); 

     // some code here calls changeWP(wxCommandEvent&) from time to time 
    } 

    void MyFrame::fillBuffer() 
    { 
     while(ImgBuffer.size() <= MaxImgBufferSize) 
     { 
      fillBufferFun(); 
     } 
    } 

void MyFrame::fillBufferFun() 
{ 
    ImgBuffer* img; 
    // do something with img 
    _beginthread(pushImgBuffer, 0, img); 
} 

void MyFrame::pushImgBuffer(void *p) 
{ 
    EnterCriticalSection(&Section); 
    ImgBuffer.push_back((IplImage*) p); 
    LeaveCriticalSection(&Section); 
} 

static unsigned int __stdcall getImgFromBuffer(void *); 

void MyFrame::changeWP(wxCommandEvent&) 
{ 
    // do someting 

    IplImage* img = NULL;// new IplImage; 
     _beginthreadex(NULL, 0, MyFrame::getImgFromBuffer, img, 0, NULL); 

     // do something with img 
     fillBuffer(); 
} 

unsigned int MyFrame::getImgFromBuffer(void *p) 
{ 
    EnterCriticalSection(&Section); 
    p = (void *)ImgBuffer[0]; 
    ImgBuffer.erase(ImgBuffer.begin()); 
    LeaveCriticalSection(&Section); 
    return 0; 
} 

回答

1

有幾個問題在這裏:

  1. 您的代碼崩潰,因爲你的getImgFromBuffer函數沒有你似乎打算爲它的效果。看起來,從查看getImgFromBuffer的主體,你試圖從vector中複製一個指針值(MyFrame :: ImgBuffer)並使用它覆蓋從調用它的函數傳入的指針值(即「 img「變量在MyFrame :: changeWP中)。由於在調用getImgFromBuffer之前初始化MyFrame :: changeWP(IplImage * img = new IplImage)中的「img」變量,我會說「似乎」 - 爲什麼在分配另一個不同的對象之前將新對象分配給指針指向它的值(當然,導致內存泄漏)?無論如何,該賦值當前只是覆蓋了getImgFromBuffer函數中的「p」參數的值,該值通過值傳遞,並且在函數退出時將丟失。如果你想getImgFromBuffer覆蓋指針變量從它的調用者傳遞的,那麼你就需要通過指針指針變量,像這樣:
void MyFrame::changeWP(wxCommandEvent&) 
{ 
    IplImage* img = NULL; // No memory leak, this time. 
    _beginthread(MyFrame::getImgFromBuffer, 0, & img); 
    //... 
} 

void MyFrame::getImgFromBuffer(void ** p) 
{ 
    //... 
    *p = (void *)ImgBuffer[0]; 
    //... 
} 
  1. 我不看看「Section」是如何定義的,但無論它是靜態的還是實例的,它至少都是不好的形式。如果它是靜態的,那麼你在每次構建時都犯了重新初始化的錯誤。我意識到這是一個代表頂級窗口的類,所以你可能不會超過其中一個,但它仍然是一個糟糕的形式。如果Section是一個實例變量,那麼您可以讓多個Section對象試圖保護單個(靜態)資源,而不會互相排斥。再次,只有一個窗口,所以這可能不是你的實際問題,但仍然...

有可能更多,但這已經足以開始。

+0

我試過你的建議。當我將MyFrame :: getImgFromBuffer(void * p)的函數定義更改爲MyFrame :: getImgFromBuffer(void ** p)時,_beginthread(MyFrame :: getImgFromBuffer,0,​​)抱怨getImgFromBuffer(void ** p)應該是getImgFromBuffer(void * p)。順便說一下,段被定義爲全局的 – CodeAsIGo 2011-03-05 17:40:29

+0

我的錯。是的,你應該保留getImgFromBuffer的簡單「void * p」簽名,然後將指針轉換爲實際的(兩次間接的)指針類型,像這樣:「IplImage ** img_ptr = static_cast (p);」然後使用類型安全的指針指針來指定想要冒泡的值,如下所示:「* img_ptr = ImgBuffer [ 0];「。在開頭注意星號。 – Jollymorphic 2011-03-06 01:14:44