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

#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;
}

时间: 2024-10-13 13:22:33

【转】gtk+多线程的程序实例的相关文章

[.net&#160;面向对象程序设计进阶]&#160;(16)&#160;多线程(Multithreading)(一) 使用多线程提高程序性能

[.net 面向对象程序设计进阶] (16) 多线程(Multithreading)(一) 使用多线程提高程序性能 本节导读: 多线程(Multithreading)使我们程序可以同时进行多任务处理,直接提高了程序的执行效率,学习多线程对提高程序运行能力非常必要,本节主要介绍多线程原理及.NET中多线程的应用. 1. 关于多线程 在介绍多线程之前,先了解一下进程. 进程:独立运行的程序称为进程.(比如Windows系统后台程序,也可以称为后台进程) 线程:对于同一个程序分为多个执行流,称为线程.

[.net 面向对象程序设计进阶] (18) 多线程(Multithreading)(三) 利用多线程提高程序性能(下)

[.net 面向对象程序设计进阶] (18) 多线程(Multithreading)(二) 利用多线程提高程序性能(下) 本节导读: 上节说了线程同步中使用线程锁和线程通知的方式来处理资源共享问题,这些是多线程的基本原理. .NET 4.0以后对多线程的实现变得更简单了. 本节主要讨论.NET4.0多线程的新特性——使用Task类创建多线程. 读前必备: A. LINQ使用  [.net 面向对象编程基础] (20) LINQ使用 B. 泛型          [.net 面向对象编程基础] (

Cr多线程编程简单实例

国家using System; using System.Collections;using System.Collections.Generic;using System.Threading; /// <summary>/// 在开发中经常会遇到线程的例子,如果某个后台操作比较费时间,我们就可以启动一个线程去执行那个费时的操作,同时程序继续执行.在某些情况下可能会出现多个线程的同步协同的问题,下面的例子就展示了在两个线程之间如何协同工作.//////这个程序的思路是共同做一件事情(从一个Ar

微信小程序实例教程(一)

序言 开始开发应用号之前,先看看官方公布的「小程序」教程吧!(以下内容来自微信官方公布的「小程序」开发指南) 本文档将带你一步步创建完成一个微信小程序,并可以在手机上体验该小程序的实际效果.这个小程序的首页将会显示欢迎语以及当前用户的微信头像,点击头像,可以在新开的页面中查看当前小程序的启动日志. 1. 获取微信小程序的 AppID 首先,我们需要拥有一个帐号,如果你能看到该文档,我们应当已经邀请并为你创建好一个帐号.注意不可直接使用服务号或订阅号的 AppID. 利用提供的帐号,登录https

Python学习笔记四:列表,购物车程序实例

列表 切片 中括号,逗号分隔,可以一次取出多个元素,起始位置包括,结束位置不包括(顾头不顾尾) 如果取最后一个,而且不知道列表长度,可以使用负数(-1是最后一个,以此类推) 如果取最后几个,记住从左往右数着取值,顾头不顾尾,所以如果取最后两个应该是[-2:] 从前取,如果是从0 开始,也可以省略 追加元素 a_list.append(value) 插入元素到任意位置 a_list.insert(index,value) 修改元素 a_list[index]=value 删除元素 a_list.r

使用 Bluemix? Live Sync 快速更新 Bluemix 上运行的应用程序实例

如果您要构建 Node.js 应用程序,那么可以使用 IBM® Bluemix® Live Sync 快速更新 Bluemix 上的应用程序实例,并像在桌面上进行操作一样进行开发,而无需重新部署.执行更改后,您可以立即在运行中的 Bluemix 应用程序中看到该更改.Bluemix Live Sync 可从命令行以及在 Web IDE 中运行.您可以使用 Bluemix Live Sync 来调试以 Node.js 编写的应用程序. Bluemix Live Sync 由三个功能部件组成 桌面同

多线程同步程序的测试思路

这里我有一个简单的思路,来源于去年应届生找工作做大量的名企笔试题里他人的技巧. 多线程的测试使用cout是不靠谱的,因为多个线程使用cout很容易产生混乱的输出,而且耗时. 多线程的测试往往需要知道多个线程同时运行的时候对某个共享区域的使用是否正确,为了检验正确性,比较好的测试用例就是:递增的整数序列 递增的整数序列中的每一个整数都对应一个线程的动作,最后我们将这些整数再当成另一个标记数组的下标,下标对应的值就是我们操作的动作执行的次数 只要用于标记的数组每一个元素都是1,即可. 比如: (1)

Linux Epoll介绍和程序实例

1. Epoll是何方神圣? Epoll但是当前在Linux下开发大规模并发网络程序的热门人选,Epoll 在Linux2.6内核中正式引入,和select类似,事实上都I/O多路复用技术而已,并没有什么神奇的. 事实上在Linux下设计并发网络程序,向来不缺少方法,比方典型的Apache模型(Process Per Connection,简称PPC),TPC(Thread PerConnection)模型,以及select模型和poll模型,那为何还要再引入Epoll这个东东呢?那还是有得说说

多次单击快捷方式,只运行一个程序实例

在应用程序安装之后,单击一次快捷方式,就运行一个程序实例,对于资源独占型程序来说,这样是不可以的,比如该程序使用了当前系统的某个端口,当同样的程序再次运行,再次试图占用同一个端口次,会提示"端口已经被占用的"异常.如此,必须在启动应用程序时,必须判断该程序是否已经有一个实例在运行.下面这个类中先判断该程序的实例有没有在运行,使用线程同步类EventWaitHandle(Boolean, EventResetMode, String)及注册正在等待 WaitHandle 的委托方法Reg