【问题标题】:How to use Fl::awake in the FLTK Library如何在 FLTK 库中使用 Fl::awake
【发布时间】:2011-11-09 17:42:05
【问题描述】:

我想使用 Fl::awake(callback) 函数在 FLTK 程序中从我的主循环调用函数。我从子线程调用 Fl::awake,它返回 1(成功),但我的函数永远不会被调用。我在主线程的循环中调用 Fl::wait() 。有什么办法可以解决这个问题吗?

【问题讨论】:

    标签: c++ fltk


    【解决方案1】:

    下面的代码是一个使用 Fl::awake(callback) 的相对简单的 FLTK 1.3 应用程序示例。代码来自 FLTK 的测试目录。只需获取源代码,您就会发现许多示例。你没有给我们你的代码,但我假设你没有在你的线程中调用Fl::lock(),后来又调用了Fl::unlock()。这是必不可少的,因为您不应访问该部分之外的小部件...

    包括

    #if HAVE_PTHREAD || defined(WIN32)
    #  include <FL/Fl.H>
    #  include <FL/Fl_Double_Window.H>
    #  include <FL/Fl_Browser.H>
    #  include <FL/Fl_Value_Output.H>
    #  include <FL/fl_ask.H>
    #  include "threads.h"
    #  include <stdio.h>
    #  include <math.h>
    
    Fl_Thread prime_thread;
    
    Fl_Browser *browser1, *browser2;
    Fl_Value_Output *value1, *value2;
    int start2 = 3;
    
    void magic_number_cb(void *p)
    {
      Fl_Value_Output *w = (Fl_Value_Output*)p;
      w->labelcolor(FL_RED);
      w->redraw_label();
    }
    
    void* prime_func(void* p)
    {
      Fl_Browser* browser = (Fl_Browser*) p;
      Fl_Value_Output *value;
      int n;
      int step;
      char proud = 0;
    
      if (browser == browser2) {
    n      = start2;
    start2 += 2;
    step   = 12;
    value  = value2;
      } else {
    n     = 3;
    step  = 2;
    value = value1;
      }
    
      // very simple prime number calculator !
      //
      // The return at the end of this function can never be reached and thus 
      // will generate a warning with some compilers, however we need to have 
      // a return statement or other compilers will complain there is no return 
      // statement. To avoid warnings on all compilers, we fool the smart ones 
      // into beleiving that there is a chance that we reach the end by testing 
      // n>=0, knowing that logically, n will never be negative in this context.
      if (n>=0) for (;;) {
    int pp;
    int hn = (int)sqrt((double)n);
    
    for (pp=3; pp<=hn; pp+=2) if ( n%pp == 0 ) break;
    if (pp >= hn) {
      char s[128];
      sprintf(s, "%d", n);
    
      // Obtain a lock before we access the browser widget...
      Fl::lock();
    
      browser->add(s);
      browser->bottomline(browser->size());
      if (n > value->value()) value->value(n);
      n += step;
    
      // Release the lock...
      Fl::unlock();
    
      // Send a message to the main thread, at which point it will
      // process any pending redraws for our browser widget.  The
      // message we pass here isn't used for anything, so we could also
      // just pass NULL.
      Fl::awake(p);
      if (n>10000 && !proud) {
        proud = 1;
        Fl::awake(magic_number_cb, value);
      }
    } else {
      // This should not be necessary since "n" and "step" are local variables,
      // however it appears that at least MacOS X has some threading issues
      // that cause semi-random corruption of the (stack) variables.
      Fl::lock();
      n += step;
      Fl::unlock();
    }
      }
      return 0L;
    }
    
    int main(int argc, char **argv)
    {
      Fl_Double_Window* w = new Fl_Double_Window(200, 200, "Single Thread");
      browser1 = new Fl_Browser(0, 0, 200, 175);
      w->resizable(browser1);
      value1 = new Fl_Value_Output(100, 175, 200, 25, "Max Prime:");
      w->end();
      w->show(argc, argv);
      w = new Fl_Double_Window(200, 200, "Six Threads");
      browser2 = new Fl_Browser(0, 0, 200, 175);
      w->resizable(browser2);
      value2 = new Fl_Value_Output(100, 175, 200, 25, "Max Prime:");
      w->end();
      w->show();
    
      browser1->add("Prime numbers:");
      browser2->add("Prime numbers:");
    
      // Enable multi-thread support by locking from the main
      // thread.  Fl::wait() and Fl::run() call Fl::unlock() and
      // Fl::lock() as needed to release control to the child threads
      // when it is safe to do so...
      Fl::lock();
    
      // Start threads...
    
      // One thread displaying in one browser
      fl_create_thread(prime_thread, prime_func, browser1);
    
      // Several threads displaying in another browser
      fl_create_thread(prime_thread, prime_func, browser2);
      fl_create_thread(prime_thread, prime_func, browser2);
      fl_create_thread(prime_thread, prime_func, browser2);
      fl_create_thread(prime_thread, prime_func, browser2);
      fl_create_thread(prime_thread, prime_func, browser2);
      fl_create_thread(prime_thread, prime_func, browser2);
    
      Fl::run();
    
      return 0;
    }
    #else
    #  include <FL/fl_ask.H>
    
    int main() {
      fl_alert("Sorry, threading not supported on this platform!");
    }
    #endif // HAVE_PTHREAD || WIN32
    

    【讨论】:

    • 我实际上不调用 lock 和 unlock 因为我不访问主线程之外的小部件。我只是使用 awake 作为信号机制。不过,main 中的 lock 调用可以修复它,感谢您为我指明正确的方向。
    • 注意:这段代码让“处理”线程在后台运行,同时让 GUI 仍然响应,但是这个实现可以让处理线程被无响应的 GUI 挂起。例如,如果您调整窗口大小并在调整大小时只是拖动鼠标,质数的计算将停止,直到您停止创建 GUI 事件。调用 Fl::awake() 并不能避免该问题,因为您仍然需要锁定/解锁以使主线程注意到 awake() 事件。所以,如果你想让你的“处理”线程不受 GUI 的影响,你就不能进行任何 FLTK 调用。
    • 有点不相关,但让我补充一下:在 main 函数中调用 Fl::lock() 非常重要。 我试图编写一个没有该调用的程序,它由于争用而无法正常工作。
    猜你喜欢
    • 2014-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多