我有一个弹出菜单,以流体产生一个所谓单线程应用FLTK。我有一个类的子类Fl_Gl_Window并实现handle()方法。手柄()方法调用创建上单击鼠标右键的弹出窗口的功能。我有一个很长的操作,我的菜单项做。我的应用程序创造了一些其他用途的第二个线程。我用锁来保护我的主线程和第二线之间的一些关键部分。特别地,doLongOperation()使用的锁。

我的问题是,我可以两次弹出菜单和运行两次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.

}
有帮助吗?

解决方案

请确保你是不是从多个线程调用Fl::wait(...)我说得对不对,从你的代码推断在自己的线程run()执行?

Fl::wait()的第一呼叫,例如从主线程,将捕捉和处理第一右击(阻塞,如预期的,而在第一次调用doLongOperation()收益);在此期间,第二个线程调用如Fl::wait(timeout)/Fl::check()将继续刷新显示 - 并将拦截(和服务)的第二右击,调用handle()(在第二个线程),而第一长操作仍在跋涉一起。这将使死锁的外观,虽然我期望UI将恢复重绘(通过第二个线程),当两个长操作完成。

验证上述登录内部popup_menu()当前线程ID。

您应该选择一个线程调用Fl::wait(...)在一个循环,你不应该阻止循环 - 产卵任何非模态或非UI任务作为独立的线程。即当popup_menu()被调用,打完折在自己的线程的运行时间长;如果popup_menu()被触发(再次),而长操作线程仍在运行,无论是纪念弹出菜单项为禁用(类似于你的解决方法),或者干脆信号长时间操作线程重新启动一个新的参数。

其他提示

以任何机会,贵doLongOperation做任何事情,可能需要消息泵(或装甲运兵车,一些Windows的文件API使用这些下)在运行(假设你看到在Windows上的行为)?例如,如果doLongOperation尝试更新使用下面SendMessage图形用户界面,你会得到僵局即使在单线程的情况。

此外,没有其他线程已临界段已经权利?你应该能够在杭期间在调试器打破,并希望看到谁在等待什么。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top