通用跨平台库glib如何设计跨平台线程库?
(2) Linux 平台函数调用链
先来看一下 Linux 平台上的函数调用关系:
如果你的手边有源代码,请关注 g_thread_new() 这个函数中的 func 和 data 这2个参数。
func 是最开始用户层传入的线程执行函数,也就是用户创建这个线程,最终想执行的函数。data 是 func 函数所接收的函数参数。
如果直接面对 Linux 操作系统编程,在调用 POSIX 接口函数 pthread_create() 时,一般是直接传入用户想要执行的函数以及参数。
但是 glib 层并没有直接把用户层的函数直接交给 Linux 操作系统,而是自己提供了 2 个线程代理函数,在调用 pthread_create() 时,根据不同的情况,把这2个代理函数之一传递给操作系统:
第一个线程代理函数:g_thread_proxy();
第二个线程代理函数:linux_pthread_proxy();
至于传递哪一个代理函数,取决于宏定义 HAVE_SYS_SCHED_GETATTR 是否有效。
下面是 g_system_thread_new() 函数简化后的代码:
g_system_thread_new (proxy, stack_size, scheduler_settings,
name, func, data, error);
GThreadPosix *thread;
GRealThread *base_thread;
// 填充 base_thread 字段,重点关注下面2句
base_thread->thread.func = func;
base_thread->thread.data = data;
thread->scheduler_settings = scheduler_settings;
thread->proxy = proxy;
#if defined(HAVE_SYS_SCHED_GETATTR)
ret = pthread_create (&thread->system_thread, &attr, linux_pthread_proxy, thread);
#else
ret = pthread_create (&thread->system_thread, &attr, (void* (*)(void*))proxy, thread);
#endif
4. 线程的执行
我们就假设这个宏定义 HAVE_SYS_SCHED_GETATTR 被定义了、是有效的,Linux 系统中的 pthread_create() 接收到 linux_pthread_proxy() 函数。
当这个新建的线程被调度执行时,linux_pthread_proxy() 函数被调用执行:
简化后的 linux_pthread_proxy() 函数:
static void *
linux_pthread_proxy (void *data)
{
// data 就是 g_system_thread_new 中 GThreadPosix 类型指针,这是平台相关的。
GThreadPosix *thread = data;
if (thread->scheduler_settings)
{
// 设置线程属性
tid = (pid_t) syscall (SYS_gettid);
res = syscall (SYS_sched_setattr, tid, thread->scheduler_settings->attr, flags);
}
// 调用 glib 中的线程代理函数,其实就是 g_thread_proxy()
return thread->proxy (data);
}
这个函数关注 3 点:
data 参数: 就是 g_system_thread_new 函数中的GThreadPosix类型指针,这是平台相关的。
中间部分是设置线程属性;
最后的 return 语句,调用了 glib 中第一个线程代理函数 g_thread_proxy。
继续贴一下这个函数的简化后代码:
gpointer
g_thread_proxy (gpointer data)
{
// data 就是 g_system_thread_new 中 GThreadPosix 类型指针,这是平台相关的。
// 这里把它强转成平台无关的 GRealThread 类型。
GRealThread* thread = data;
if (thread->name)
{
// 设置线程属性:名称
g_system_thread_set_name (thread->name);
}
// 调用应用层的线程入口函数
thread->retval = thread->thread.func (thread->thread.data);
return NULL;
}
这个函数也只要关注 3 点:
data 参数: linux_pthread_proxy 函数传过来的是 GThreadPosix 类型指针,但是这里直接赋值给了 GRealThread 类型的指针,因为它们的内存模型是包含的关系;
中间部分是设置线程名称;
最后的 thread->thread.func (thread->thread.data) 语句,调用了用户最开始传入的函数并传递用户的 data 参数。
至此,用户层定义的线程函数 user_thread_func(data) 就得以执行了。
那么,如果 glib 层没有定义宏 HAVE_SYS_SCHED_GETATTR,那么 Linux 系统中 pthread_create() 接收到的就是 glib 中的第一个线程代理函数 g_thread_proxy。
线程执行的调用关系为:
5. Windows平台函数调用链
先来看一下 Windows 平台上创建线程时函数调用关系:
在 Windows 平台上,glib 的线程代理函数是 g_thread_win32_proxy()。
当这个新建的线程被调度执行时,函数调用关系是:
四、总结
实现这样的线程函数代理设计,关键是利用了 C 语言中的结构体类型中,把“父”结构体类型变量强制转换成“子”结构体类型变量来使用,因为它俩在内存模型中,刚开始部分的空间中,内容是完全一样的。
最后,我把文中的这些图合并起来,绘制成下面这 2 张图,完整的体现了 glib 中的线程设计思路:
Linux 平台:
Windows 平台:
图片新闻
最新活动更多
-
11月22日立即报名>> 【线下论坛】华邦电子与莱迪思联合技术论坛
-
即日-11.30免费预约申请>>> 燧石技术-红外热成像系列产品试用活动
-
11月30日立即试用>> 【有奖试用】爱德克IDEC-九大王牌安全产品
-
即日-12.26火热报名中>> OFweek2024中国智造CIO在线峰会
-
限时免费下载立即下载 >>> 2024“机器人+”行业应用创新发展蓝皮书
-
即日-2025.8.1立即下载>> 《2024智能制造产业高端化、智能化、绿色化发展蓝皮书》
推荐专题
- 1 同源共创 模式革新 | 华天软件皇冠CAD(CrownCAD)2025新品发布会圆满举行
- 2 上海国际嵌入式展暨大会(embedded world China )与多家国际知名项目达成合作
- 3 iEi威强电新品丨IMBA-AM5:工业计算的强劲引擎
- 4 史上首次,大众终于熬不住开启40亿降本计划!关3个工厂,裁员万名...
- 5 守护绿色学习空间,EK超低温热泵服务对外经济贸易大学图书馆
- 6 颜值高 有“门”道|贝特威汽车门板内饰AI视觉检测解决方案
- 7 观众登记启动 优解制造未来,锁定2025 ITES深圳工业展
- 8 “秸”尽全力,防患未“燃” | 秸秆焚烧智能监控解决方案
- 9 揭秘:「全球知名跨境电商」构建核心竞争力的“独门绝技”是?
- 10 3大场景解读 | 红外热像仪赋能科研智造创新应用
发表评论
请输入评论内容...
请输入评论/评论长度6~500个字
暂无评论
暂无评论