基于glib的单线程多事件源处理

传统实现程序命令行的输入一般使用scanf或者getchar系统调用,这样,要求程序实现时要使用一个独立的线程检测用户的输入,这样就涉及到多线程编程的一系列问题。glib的mainloop机制可以提供单线程多事件源的注入,只要我们将用户的输入转换成GSource,就可以实现一种单线程的既可以响应用户输入,同时又能在输入的间隙处理其它事件的类并发模型。
1、基本概念
1.1 GMainContext
1.2 GMainLoop
1.3 GSource
1.4 Poll机制
1.5 File Descriptor
2、实现
2.1 创建一个GMainLoop
loop = g_main_loop_new (NULL, FALSE);
参数说明:
NULL指的是GMainLoop基于的GMainContext,NULL参数表示该mainloop基于glib的default context。
2.2 创建一个GSource
2.2.1 为GSource提供一个回调函数结构体
static gboolean prepare( GSource * source, gint * timeout_ )
{
    * timeout_  =   -1;


    return FALSE;
}


static gboolean check( GSource * source )
{
  gboolean _result    =   FALSE;




if( fd.revents == POLLIN )
{
_result =   TRUE;
}


return _result;
}




static gboolean dispatch( GSource * source, GSourceFunc callback, gpointer user_data )
{
    gchar _cmd[100]  =   {0};


    read( 0, _cmd, sizeof( _cmd ));


    switch( _cmd[0] )
    {
    case 'h':
        printUsage();
        break;
    case 'p':
        break;
    case 'x':
        g_main_loop_quit (loop);
        break;
    case '>':
        break;
    case '<':
        break;
    default:
        break;
    }




printf( ">" );
fflush( stdout );


return G_SOURCE_CONTINUE;
}
static GSourceFuncs funcs   =
{
    .prepare    =   prepare,
    .check      =   check,
    .dispatch   =   dispatch
};
2.2.2 为GSource提供stdin fd
static GPollFD fd   =
{
    .fd =   0,
    .events =   POLLIN,
    .revents    =   0
};
2.2.3 创建GSource
_source =   g_source_new( &funcs, sizeof( GSource ));
g_source_attach( _source, NULL );
2.2.4 为GSource添加stdin fd
g_source_add_poll( _source, &fd );
2.2.5 释放GSource引用
g_source_unref( _source );//一定要做,否则会内存泄漏
2.3 运行GMainLoop
g_main_loop_run (loop);


至此,命令行接口已创建完毕,程序运行后,用户可以通过控制台输入命令。开发者后续可以在mainloop上附加其它的GSource,使这个mainloop可以处理额外的并发事件。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的例子,演示如何将自己库的glib主循环运行到指定的线程中,并保证自己库内部的事件处理在自己指定的主循环中: ```c #include <glib.h> #include <pthread.h> // 自己库的事件处理上下文 static GMainContext *my_context = NULL; // 自己库的主循环 static GMainLoop *my_loop = NULL; // 自己库的事件处理函数 static gboolean my_callback(gpointer data) { // 处理事件 g_print("my_callback called\n"); // 返回FALSE表示不再监听该事件 return FALSE; } // 自己库的初始化函数 void my_library_init() { // 创建自己库的事件处理上下文 my_context = g_main_context_new(); // 添加需要处理事件到自己库的事件处理上下文 GSource *source = g_timeout_source_new(1000); g_source_set_callback(source, my_callback, NULL, NULL); g_source_attach(source, my_context); g_source_unref(source); // 将自己库的事件处理上下文和主循环进行关联 g_main_context_push_thread_default(my_context); } // 自己库的线程函数 void *my_library_thread(void *data) { // 创建自己库的主循环 my_loop = g_main_loop_new(my_context, FALSE); // 运行自己库的主循环 g_main_loop_run(my_loop); return NULL; } // 主程序函数 int main(int argc, char *argv[]) { // 初始化GLib库 g_thread_init(NULL); g_type_init(); // 初始化自己库 my_library_init(); // 创建自己库的线程 pthread_t tid; pthread_create(&tid, NULL, my_library_thread, NULL); // 主程序的事件处理上下文 GMainContext *main_context = g_main_context_default(); // 添加需要处理事件到主程序的事件处理上下文 GSource *source = g_timeout_source_new(500); g_source_set_callback(source, (GSourceFunc)g_main_loop_quit, my_loop, NULL); g_source_attach(source, main_context); g_source_unref(source); // 在主程序的事件处理上下文中监听自己库的事件 while (1) { g_main_context_iteration(main_context, TRUE); } return 0; } ``` 在该例子中,我们创建了一个自己库的事件处理上下文和主循环,并将需要处理事件添加到该上下文中。然后,在主程序中,我们在主程序的事件处理上下文中添加了一个定时器事件,用于退出自己库的主循环。最后,在主程序的事件处理上下文中使用g_main_context_iteration()函数来监听自己库的事件。在自己库的线程函数中,我们使用g_main_loop_run()函数来运行自己库的主循环,确保自己库的事件处理都在自己指定的主循环中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值