【转】gtk+多线程的程序实例

简介: #include gint test() {     while(1)        {               gdk_threads_enter();               g_printf("hello\n");               gdk_threads_l...

#include <gtk/gtk.h>

gint test()

{

    while(1)

       {

              gdk_threads_enter();

              g_printf("hello\n");

              gdk_threads_leave();

       };

    return TRUE;

}

gint timeout_callback( gpointer data )

{

       g_thread_create(test, NULL, FALSE, NULL);

       return FALSE;

}

/*这是一个回调函数。data参数在本示例中被忽略。

*后面有更多的回调函数示例。*/

void hello( GtkWidget *widget,

            gpointer   data )

{

    g_print ("Hello World\n");

}

gint delete_event( GtkWidget *widget,

                   GdkEvent *event,

                 gpointer   data )

{

    /*如果你的"delete_event"信号处理函数返回FALSE,GTK会发出"destroy"信号。

     *返回TRUE,你不希望关闭窗口。

     *当你想弹出“你确定要退出吗?”对话框时它很有用。*/

    g_print ("delete event occurred\n");

    /*改TRUE为FALSE程序会关闭。*/

    return TRUE;

}

/*另一个回调函数*/

void destroy( GtkWidget *widget,

              gpointer   data )

{

    gtk_main_quit ();

}

int main( int   argc,

          char *argv[] )

{

    /* GtkWidget是构件的存储类型*/

    GtkWidget *window;

    GtkWidget *button;

       if(!g_thread_supported()) g_thread_init(NULL);

       gdk_threads_init();

       /*这个函数在所有的GTK程序都要调 用。参数由命令行中解析出来并且送到该程序中*/

    gtk_init (&argc, &argv);

   

    /*创建一个新窗口*/

    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

   

    /*当窗口收到"delete_event"信号(这个信号由窗口管理器发出,通常是“关闭”

     *选项或是标题栏上的关闭按钮发出的),我们让它调用在前面定义的delete_event()函数。

     *传给回调函数的data参数值是NULL,它会被回调函数忽略。*/

    g_signal_connect (G_OBJECT (window), "delete_event",

                    G_CALLBACK (delete_event), NULL);

   

    /*在这里我们连接"destroy"事 件到一个信号处理函数。

     *对这个窗口调用gtk_widget_destroy()函数或在"delete_event"回调函数中返回FALSE值

     *都会触发这个事件。*/

    g_signal_connect (G_OBJECT (window), "destroy",

                    G_CALLBACK (destroy), NULL);

   

    /*创建一个标签为"Hello World"的新按钮。*/

    button = gtk_button_new_with_label ("Hello World");

   

    /*当按钮收到"clicked"信 号时会调用hello()函数,并将NULL传给

     *它作为参数。hello()函数 在前面定义了。*/

    g_signal_connect (G_OBJECT (button), "clicked",

                    G_CALLBACK (hello), NULL);

   

    /*当点击按钮时,会通过调用gtk_widget_destroy(window)来关闭窗口。

     * "destroy"信号会从这里或从窗口管理器发出。*/

    g_signal_connect_swapped (G_OBJECT (button), "clicked",

                           G_CALLBACK (gtk_widget_destroy),

                              window);

   

    /*把按钮放入窗口(一个gtk容器)中。*/

    gtk_container_add (GTK_CONTAINER (window), button);

   

    /*最后一步是显示新创建的按钮和窗口*/

    gtk_widget_show (button);

    gtk_widget_show (window);

    gtk_timeout_add(1, timeout_callback, NULL);

    /*所有的GTK程序必须有一 个gtk_main()函数。程序运行停在这里

     *等待事件(如键盘事件或鼠标 事件)的发生。*/

      

    gdk_threads_enter();

    gtk_main ();

    gdk_threads_leave();    

    return 0;

}

 

 

#include <gtk/gtk.h>

static GtkWidget *fixed;

static GtkWidget *button1;

static GtkWidget *button2;

int running = 1;

void our_thread1(GtkWidget *button)

{

 gint x,y,towards;

 x=40;

 y=40;

 towards=1;

 while (running)

 {

     g_usleep(1); //一定要加

  gdk_threads_enter(); //在需要与图形窗口交互的时候加

  gtk_fixed_move(GTK_FIXED(fixed),button,x,y); 

  switch(towards)

  {

  case 1:

   x=x+10;

   if (x==250) towards=2;

   break;

  case 2:

   y=y+10;

   if (y==250) towards=3;

   break;

  case 3:

   x=x-10;

   if (x==40) towards=4;

   break;

  case 4:

   y=y-10;

   if (y==50) towards=5;

  }

  gdk_threads_leave();  //搭配上面的

 }

}

 

void on_begin(GtkWidget* button,gpointer data)

{

     gtk_widget_set_sensitive(button,FALSE);

     g_thread_create(our_thread1,button1,FALSE,NULL); 

}

void *run_f(GtkWidget *butt,gpointer data)

{

    running = 0;

}

 

int main(int argc,char* argv[])

{

     GtkWidget *window,*view;

     GtkWidget *vbox,*button,*label;

 

     if (!g_thread_supported())

      g_thread_init(NULL);

 

     gdk_threads_init();

 

     gtk_init(&argc,&argv);

     window=gtk_window_new(GTK_WINDOW_TOPLEVEL);

     gtk_window_set_title(GTK_WINDOW(window),"thread apllication");

     g_signal_connect(G_OBJECT(window),"delete_event",

          G_CALLBACK(gtk_main_quit),NULL);

     gtk_container_set_border_width(GTK_CONTAINER(window),10);

     vbox=gtk_vbox_new(FALSE,0);

     gtk_container_add(GTK_CONTAINER(window),vbox);

     label=gtk_label_new("Notice! Button is moving");

     gtk_box_pack_start(GTK_BOX(vbox),label,FALSE,FALSE,0);

     view=gtk_viewport_new(NULL,NULL);

     gtk_box_pack_start(GTK_BOX(vbox),view,FALSE,FALSE,0);

     fixed=gtk_fixed_new(); 

     gtk_widget_set_usize(fixed,330,330); 

     gtk_container_add(GTK_CONTAINER(view),fixed);

     button1=gtk_button_new_with_label("1");

     gtk_fixed_put(GTK_FIXED(fixed),button1,10,10); 

 

     button=gtk_button_new_with_label("Start");

     gtk_box_pack_start(GTK_BOX(vbox),button,FALSE,FALSE,5);

     g_signal_connect(G_OBJECT(button),"clicked",

          G_CALLBACK(on_begin),NULL);                // call on_begin

   

     GtkWidget *run = gtk_button_new_with_label("stop");

     gtk_box_pack_start(GTK_BOX(vbox),run,FALSE,FALSE,5);

     g_signal_connect(G_OBJECT(run),"clicked",

          G_CALLBACK(run_f),NULL);                // call on_begin

 

     gtk_widget_show_all(window);

     gdk_threads_enter();

     gtk_main();

     gdk_threads_leave();

     return FALSE;

}

 

 

 

我们知道glib提供了一个名为g_idle_add的 函数,这个函数的功能很容易理解:增加一个空闲任务,让应用程序在空闲时执行指定的函数。 这种机制非常有用,如果没有这种机制,很多事情将非常麻烦。它的功能虽然简单,但并不是所有人都知道如何充分发挥它的潜力,这里说说它的几个主要用途吧。

1.在空闲时执行低优先级任务。有的任务优先级比较低,但费耗时间比较长,像屏幕刷新等操作,我们不希望它阻碍当前操作太久,此时 可以把它放到空闲任务里去做。实际上GTK+里面也是这样做的,这样可以获得 更好的响应性。

2.将同步操作异步化。我们知道在GTK+中,它使用glib的signal作为窗口/控件之间的通信方式,signal的执行是直接调用函数,即整个signal的执行过程是同步完成的。这在多数情况下工作得很好,但有时会出现重入的问题,你调我,我再调你,可 能会遇到麻烦。此时我们不得不采用异步方式,而GTK+没有提供像Win32下的PostMessage之类的异 步消息,幸好我们可以用g_idle_add函数来模拟。

3.串行化对GUI的访问。在大 多数平台下,对GUI资源的访问都是需要串行化的,即在一个GUI应用程序中,只有一个线程可以直接操作GUI资源。这是因为出于效率的考虑,GUI资源是没有加锁保护的,GTK+也是这样的。如果另外一个线程要访问GUI资源,比如要显示一条信息,怎么办呢?这可以通过g_idle_add增加一个空闲任务来实现,idle任务是GUI线程(主线程)中执行的,所以串行了对GUI资源的访问。

这里要注意,idle任务并不是一个独立的线程或者进程,而在是主线程中执行的。所谓空闲是指,当main loop没有其它消息要处理,而且没有更高优先级的工作要做时,就认为处于空闲状态。

 

网上各种文章都强烈建议,所有对于GUI的操作都在一个线程内完成,其他可能导致阻塞的工作在另外一个线程中。

所以
gdk_threads_enter();
gtk_label_set_text(GTK_LABEL(wbus->time),text);
gdk_threads_leave(); 
这样的代码应该替换为:
g_idle_add(on_finish, wbus);//子线程中。

gboolean on_finish(gpointer wbus)
{
  gtk_label_set_text(GTK_LABEL(wbus->time),text);
  return FALSE;
}

相关文章
|
12天前
|
Java 开发者
如何通过易语言多线程提升程序响应速度
如何通过易语言多线程提升程序响应速度
108 62
|
5天前
|
Java 开发者
如何通过易语言多线程提升程序响应速度?
如何通过易语言多线程提升程序响应速度?
|
5月前
|
分布式计算 并行计算 安全
在Python Web开发中,Python的全局解释器锁(Global Interpreter Lock,简称GIL)是一个核心概念,它直接影响了Python程序在多线程环境下的执行效率和性能表现
【6月更文挑战第30天】Python的GIL是CPython中的全局锁,限制了多线程并行执行,尤其是在多核CPU上。GIL确保同一时间仅有一个线程执行Python字节码,导致CPU密集型任务时多线程无法充分利用多核,反而可能因上下文切换降低性能。然而,I/O密集型任务仍能受益于线程交替执行。为利用多核,开发者常选择多进程、异步IO或使用不受GIL限制的Python实现。在Web开发中,理解GIL对于优化并发性能至关重要。
59 0
|
11天前
|
监控 Java API
|
3月前
|
Rust 并行计算 安全
揭秘Rust并发奇技!线程与消息传递背后的秘密,让程序性能飙升的终极奥义!
【8月更文挑战第31天】Rust 以其安全性和高性能著称,其并发模型在现代软件开发中至关重要。通过 `std::thread` 模块,Rust 支持高效的线程管理和数据共享,同时确保内存和线程安全。本文探讨 Rust 的线程与消息传递机制,并通过示例代码展示其应用。例如,使用 `Mutex` 实现线程同步,通过通道(channel)实现线程间安全通信。Rust 的并发模型结合了线程和消息传递的优势,确保了高效且安全的并行执行,适用于高性能和高并发场景。
47 0
|
3月前
|
开发框架 Android开发 iOS开发
跨平台开发的双重奏:Xamarin在不同规模项目中的实战表现与成功故事解析
【8月更文挑战第31天】在移动应用开发领域,选择合适的开发框架至关重要。Xamarin作为一款基于.NET的跨平台解决方案,凭借其独特的代码共享和快速迭代能力,赢得了广泛青睐。本文通过两个案例对比展示Xamarin的优势:一是初创公司利用Xamarin.Forms快速开发出适用于Android和iOS的应用;二是大型企业借助Xamarin实现高性能的原生应用体验及稳定的后端支持。无论是资源有限的小型企业还是需求复杂的大公司,Xamarin均能提供高效灵活的解决方案,彰显其在跨平台开发领域的强大实力。
38 0
|
3月前
|
Java 调度
|
3月前
|
安全 C# 开发者
【C# 多线程编程陷阱揭秘】:小心!那些让你的程序瞬间崩溃的多线程数据同步异常问题,看完这篇你就能轻松应对!
【8月更文挑战第18天】多线程编程对现代软件开发至关重要,特别是在追求高性能和响应性方面。然而,它也带来了数据同步异常等挑战。本文通过一个简单的计数器示例展示了当多个线程无序地访问共享资源时可能出现的问题,并介绍了如何使用 `lock` 语句来确保线程安全。此外,还提到了其他同步工具如 `Monitor` 和 `Semaphore`,帮助开发者实现更高效的数据同步策略,以达到既保证数据一致性又维持良好性能的目标。
41 0
|
3月前
|
安全 Java API
揭秘Java并发编程的神秘面纱:线程安全与性能优化之间的微妙舞蹈,如何让你的程序在多核时代中翱翔!
【8月更文挑战第12天】随着多核处理器的普及,Java并发编程越发重要。线程安全确保多线程环境下的程序一致性,而性能优化则让程序高效运行。通过同步机制如`synchronized`关键字或`ReentrantLock`接口,我们可以实现线程安全,如在银行账户存款操作中限制并发访问。然而,过度同步会导致性能下降,因此采用细粒度锁和利用Java并发工具类(如`ConcurrentHashMap`)可提高程序的并发能力。理解这些概念并加以实践,是每个Java开发者提升技能的关键。
45 0