2011-03-05 77 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