GTK多线程界面更新(续)

来源:互联网 发布:游戏优化器 编辑:程序博客网 时间:2024/04/30 22:51
原文地址:http://my.oschina.net/eatapple/blog/97180
上一篇《GTK多线程更新界面》中,我提到可以通过使用空闲函数来替代多线程处理GTK。随着对GTK的了解,发现这样并不是所有情况都合适。 
    第一,如果使用空闲函数来处理socket程序,可能会造成数据接收不及时,特别是针对一些对数据及时性要求很高的程序。因为空闲函数只会在用户不对界面进行操作的时候(即系统空闲时)才进行。如果当前用户正在界面上执行某项耗时的操作,而此时有数据通过socket传送,那么该数据会等到用户的界面操作完成后才到达,造成了数据延时。那么应该怎么处理了,此时我们可以向GTK的主循环添加一个需要监视的socket描述符,然后让主循环对该socket进行扫描。这样做的效率在我看来是比使用空闲函数高的。具体使用方法: 
        1.完成socket连接。 
        2.使用g_io_channel_unix_new()生成一个全新的GChannel指针。注意:windows平台请使用g_io_channel_win32_new_socket()。 
        3.通过g_io_add_watch()将刚才的GChannel指针添加到需要检测的队列中。 
01#include <glib.h>
02#include <stdio.h>
03#include <string.h>
04#include <stdlib.h>
05#include <sys/socket.h>
06#include <sys/types.h>
07#include <arpa/inet.h>
08 
09#define ADDR "192.169.18.252"
10#define PORT 5038
11 
12int new_message(GIOChannel *channel,GIOCondition condition,gpointer data);
13 
14int main()
15{
16    GMainLoop *loop;
17    GIOChannel *channel;
18    int sockfd;
19    struct sockaddr_in addr;
20     
21    /*Create socket*/
22    sockfd=socket(AF_INET,SOCK_STREAM,0);
23     
24    /*Init address*/
25    memset(&addr,0,sizeof(addr));
26    addr.sin_family=AF_INET;
27    addr.sin_port=htons(PORT);
28    addr.sin_addr.s_addr=inet_addr(ADDR);
29 
30    /*connect to the server*/
31    if(connect(sockfd,(struct sockaddr *)&addr,sizeof(addr))==-1)
32    {
33        perror("connect");
34        return 1;
35    }
36     
37    /*Get channel from socket*/
38    channel=g_io_channel_unix_new(sockfd);
39 
40    /*add the channel to main loop*/
41    g_io_add_watch(channel,G_IO_IN|G_IO_HUP|G_IO_NVAL|G_IO_ERR,(GIOFunc)new_message,NULL);
42 
43    /*Enter the main loop*/
44    loop=g_main_loop_new(NULL,FALSE);
45    g_main_loop_run(loop);
46 
47    return 0;
48}
49 
50int new_message(GIOChannel *channel,GIOCondition condition,gpointer data)
51{
52    if(condition==G_IO_IN)
53    {
54        /*Something to read*/
55        char buffer[BUFSIZ];
56        int sockfd;
57     
58        memset(buffer,0,sizeof(buffer));
59        sockfd=g_io_channel_unix_get_fd(channel);
60        recv(sockfd,buffer,BUFSIZ,0);
61        g_print("%s",buffer);
62        return TRUE;
63    }
64    else
65    {
66        /*Unable to read ,so remove the watch*/
67        g_print("closed");
68        return FALSE;
69    }
70}

    第二,在使用空闲函数时,如果空闲函数可能存在阻塞的情况,例如,连接超时。当空闲函数超时使,程序会一直阻塞,直到空闲函数完成。为了避免这种情况,必须使用多线程。如果直接按照网上的一些例子在线程中通过使用gdk_threads_enter()和gdk_threads_leave()来更新界面,这回导致程序移植问题(在我的测试中,linux系统上是不存在问题,但是如果使用mingw则界面会出现卡钝现象)。为了解决这个问题,我的建议是只在线程中处理数据(例如treeview的model数据等),在需要处理界面时,通过gdk_threads_idle_add()函数添加界面处理。这样就解决了程序的移植和后台更新数据等问题。
原创粉丝点击