我有一個假想的單線程FLTK應用程序與彈出菜單,創建與流體。我有一個類Fl_Gl_Window子類,並實現一個handle()方法。 handle()方法調用一個函數,在右鍵單擊時創建一個彈出窗口。對於其中一個菜單項,我有很長的操作。我的應用程序爲其他目的創建了第二個線程。我使用鎖來保護主線程和第二線程之間的一些關鍵部分。特別是,doLongOperation()使用鎖。爲什麼我可以在單線程FLTK應用程序中死鎖?
我的問題是,我可以彈出菜單兩次,運行doLongOperation()兩次,然後它自己死鎖,掛起應用程序。 爲什麼第一個doLongOperation()不會拖延GUI並阻止我第二次啓動doLongOperation()?
我可以避免與我用來禁用違規菜單項的標誌的問題,但我想了解爲什麼它可能在第一個地方。
這是代碼,當然縮寫。希望我已經包含了所有相關的部分。
class MyClass {
void doLongOperation();
};
class MyApplication : public MyClass {
MyApplication();
void run();
void popup_menu();
};
void MyClass::doLongOperation()
{
this->enterCriticalSection();
// stuff
// EDIT
// @vladr I did leave out a relevant bit.
// Inside this critical section, I was calling Fl::check().
// That let the GUI handle a new popup and dispatch a new
// doLongOperation() which is what lead to deadlock.
// END EDIT
this->leaveCriticalSection();
}
MyApplication::MyApplication() : MyClass()
{
// ...
{ m_mainWindowPtr = new Fl_Double_Window(820, 935, "Title");
m_mainWindowPtr->callback((Fl_Callback*)cb_m_mainWindowPtr, (void*)(this));
{ m_wireFrameViewPtr = new DerivedFrom_Fl_Gl_Window(10, 40, 800, 560);
// ...
}
m_mainWindowPtr->end();
} // Fl_Double_Window* m_mainWindowPtr
m_wireFrameViewPtr->setInteractive();
m_mainWindowPtr->position(7,54);
m_mainWindowPtr->show(1, &(argv[0]));
Fl::wait();
}
void MyApplication::run() {
bool keepRunning = true;
while(keepRunning) {
m_wireFrameViewPtr->redraw();
m_wireFrameView2Ptr->redraw();
MyClass::Status result = this->runOneIteration();
switch(result) {
case DONE: keepRunning = false; break;
case NONE: Fl::wait(0.001); break;
case MORE: Fl::check(); break;
default: keepRunning = false;
}
}
void MyApplication::popup_menu() {
Fl_Menu_Item *rclick_menu;
int longOperationFlag = 0;
// To avoid the deadlock I can set the flag when I'm "busy".
//if (this->isBusy()) longOperationFlag = FL_MENU_INACTIVE;
Fl_Menu_Item single_rclick_menu[] = {
{ "Do long operation", 0, 0, 0, longOperationFlag },
// etc. ...
{ 0 }
};
// Define multiple_rclick_menu...
if (this->m_selectedLandmarks.size() == 1) rclick_menu = single_rclick_menu;
else rclick_menu = multiple_rclick_menu;
const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, 0);
if (!m) return;
if (strcmp(m->label(), "Do long operation") == 0) {
this->doLongOperation();
return;
}
// Etc.
}
我不是從多個線程調用wait()或check(),而是在doLongOperation()內調用Fl :: check()。它在另一個功能之內,所以它不在視線之內。 Fl :: check()讓GUI處理事件,讓我開始另一個doLongOperation()。第二個人阻止等待第一個解鎖,但第一個在第二個正在運行時被阻塞。因此,你的答案並不是確切的解決方案,但你的元點(「小心wait()和check()」)是找出我出錯的地方的觸發器,所以你得到了賞金。謝謝! – cape1232 2010-08-12 13:16:56
對不起1/2賞金。我認爲選擇你的答案就足以把它給你。我錯過了我應該明確地去做的地方。我的第一個賞金,加上錯誤,你爲此感到痛苦。生活對你來說太不公平了。 – cape1232 2010-08-19 03:12:53