APP下载

基于Linux多线程管理的分析与实现

2017-09-20李传玺

电子科技 2017年9期
关键词:掩码主线内核

孙 帅,李传玺

(航天科工深圳集团有限公司 南京分公司,江苏 南京211100)

基于Linux多线程管理的分析与实现

孙 帅,李传玺

(航天科工深圳集团有限公司 南京分公司,江苏 南京211100)

给出了一种有效防止线程并发混乱以及进程异常结束的软件设计方法,综合利用POSIX Threads库的系统功能,调整线程的默认配置、合理地规划线程结构,并正确回收子线程。实际测试结果表明,该线程管理策略是正确设计多线程结构的一种方法,具有较高的应用价值。

线程管理;线程安全;线程优先级;线程栈

目前,主流多任务操作系统大多提供线程机制[1]。利用多线程可将进程的任务划分为多个线程执行,尤其在多核处理器的环境中,线程被调度到不同的处理核上执行,使程序运行效率得到显著提高[2]。然而,由于线程自身并发的特性,各个线程竞争处理器资源以及父进程的数据资源,导致程序运行存在不确定的结果,甚至出现运行故障,这给软件设计和调试带来了较大困难。 为降低多线程软件设计的困难,确保程序运行稳定,本文从研究线程的属性开始,分析POSIX Threads库函数的作用,通过制定多线程的管理策略,达到协调线程的竞争资源,控制线程生命周期的目的。最后通过实例给出一种使用多线程设计的安全方案,讨论了多线程结构的设计要点。

1 线程属性

线程管理的内容涉及到线程的创建和终止、等待和分离、绑定内核、调度策略、同步互斥等部分[3-4]。这些属性设置对线程的执行过程产生较大的影响。

分离和绑定。线程的结合状态决定线程以何种方式来终止自己[5],其状态分为两种:非分离状态PTHREAD_CREATE_JOINABLE、分离状态PTHREAD_CREATE_DETACHED[6]。在非分离状态下,当某个线程结束后,其占用的资源并未得到释放,即线程尚未正式结束[7]。在分离状态下,线程结束时立即释放它占有的所有系统资源。线程的绑定是指用户线程固定地分配给一个内核线程,其状态分为两种:非绑定状态PTHREAD_SCOPE_PROCESS、绑定状态PTHREAD_SCOPE_SYSTEM[8]。由于CPU时间片的调度是面向轻进程的,具有绑定属性的线程可以保证在需要的时候总有一个内核线程与之对应[9],而非绑定的线程是由系统来分配内核调度。因此,绑定的线程比普通线程获得更高的响应速度。线程的默认设置是非分离、非绑定。

优先级和栈。线程的优先值影响线程之间的竞争关系,优先级取值范围是0~139,其中0~99代表实时进程;100~139代表非实时进程[10]。数值越小,优先级越高。内核采用SCHED_FIFO调度策略优先调用优先级高的线程,该线程独占处理器直到更高优先级的线程准备就绪。线程的默认设置是优先级无效。栈是每个线程独立拥有的资源,起始于父进程虚拟内存的高端地址,并向内存底端地址方向扩展[11]。系统默认为主线程分配8 MB栈资源,为子线程栈预留2 MB的寻址空间,栈的容量在线程创建后固定不变,只有主线程的栈随着线程的运行而自动增长[12]。

2 线程管理库

2.1 连接分离

实现线程分离的库函数是pthread_detach( )[13]。在任意时刻,非分离线程可被其他线程收回资源。回收过程需要被显示的调用pthread_detach( ),否则线程将进入进程的Zombie状态,其占有的部分内存无法回收,导致系统资源泄漏。正确使用分离函数的方法是在主线程中调用pthread_detach( ),或者在被等待线程中使用pthread_detach(thread_self( ))。设计多线程结构时应当根据实际需要,选择适当的分离状态。

2.2 线程绑定

实现线程绑定的库函数是pthread_attr_setaffinity_np( )[14]。该函数最后一个参数为mask,对应多核处理器的掩码。掩码的每个设置位一一对应合法调度的处理器核,相反,掩码中未设置的位则对应不可调度的处理器核。绑定的线程只能在对应位被设置的处理器核上运行。为提高线程实时性,正确使用绑定函数的方法是将有实时性需求的线程置位所有掩码,即所有处理器核均可调度。设计多线程结构时应当根据实际需要,选择具有实时任务的线程设置绑定属性。

2.3 线程优先级

实现线程优先级设定的库函数是pthread_attr_setschedparam ( )[15]。内核的调度策略包括SCHED_FIFO,SCHED_RR和SCHED_OTHER,默认使用SCHED_OTHER。线程在SCHED_OTHER策略下优先级无效。为提高线程响应速度,正确使用优先级函数的方法是首先通过pthread_attr_setschedpolicy( )设置内核调度策略为SCHED_FIFO,其次调用sched_get_priority_max( )和sched_get_priority_min( )获取线程的优先级范围,最后使用pthread_attr_setschedparam( )设置系统合法的优先级值。

2.4 线程栈

实现线程栈设定的库函数是pthread_attr_setschedparam ( )[16]。多线程共享父进程的全部资源,创建过多数量的子线程将引起父进程虚拟地址空间消耗过快,因此,栈空间分配的合理与否是线程创建失败的一个原因,也是线程运行中出现故障的重要原因,这直接导致父进程异常结束。正确使用栈函数的方法是通过管道获取进程内存的利用率,在不低于主线程最低配置的条件下,应分配给子线程足够的内存空间。设计多线程结构时应当根据实际需要,减少子线程的数量,并为已有线程提供足够的栈资源。

3 安全设计方案

通过上述对线程库分析的结果,本文给出一种使用多线程设计的安全方案,其中主线程设计结构如下

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

s = pthread_attr_init(&attr); //初始化默认属性

if (stack_size > 0) {

s = pthread_attr_setstacksize(&attr, stack_size); //设置栈属性

if (s != 0) handle_error_en(s, "pthread_attr_setstacksize");

}

for (tnum = 0; tnum < num_threads; tnum++) { //创建多个子线程

s = pthread_create( &tinfo[tnum].thread_id, &attr, &thread_start, &tinfo[tnum]);

}

for (tnum = 0; tnum < num_threads; tnum++) {

if( !tnum ) continue; //第一个线程无需回收

s = pthread_join(tinfo[tnum].thread_id, &res); //回收其他线程资源

}

free(tinfo); //释放主线程申请资源

}

主线程创建3个子线程,在调整线程参数后,分配子线程相应的资源使其可以正常执行。其中,子线程配置的内容如表1所示。在任务执行结束前,主线程需要等待子线程的结束,获取子线程运算结果,并回收其占有的全部资源。

表1 每个子线程的配置内容

子线程创建成功后开始执行同样的任务并相互竞争,由于主线程对子线程配置属性的不同,其执行的过程出现明显的差异。子线程设计结构如下

void *thread start(void *arg) {

if( !(long)arg )

{

CPU_SET(*a, &mask); //设置绑定掩码

sched_setaffinity(0, sizeof(mask), &mask); //第一个线程绑定处理器核

}

if( !(long)arg ) pthread_detach(thread_self( )); //第一个线程主动释放资源

else pthread_exit((void*)(uargv)); //其他线程返回结果,并占有资源

}

该程序运行结果如图1所示,每个子线程获取4 MB的栈资源,不同之处是第一个子线程绑定处理器核而获得了较高的响应速度,因此该线程第一个被调用并且第一个执行完成。由于第一个子线程最后主动释放了占有资源,所以主线程无需获得其运算结果,其他线程结束后由主线程回收所分配的全部资源。从图中可以得出,实例程序运行结果正常。

图1 使用终端观测到的多线程运行结果

4 结束语

提出了一种有效防止线程并发混乱以及进程异常结束的软件设计方法,结合一个实例说明了该方法的具体实现,并验证了该方法的安全性,降低了多线程结构的设计难度。经过测试,使用本方法设计的程序工作性能稳定,具备一定的工程实用性。

[1] 唐靖飚.Unix平台下C 语言高级编程指南[M].北京:希望电子出版社,2000.

[2] 魏永明.Linux 实用教程[M].北京:电子工业出版社,2000.

[3] 么丽颖.基于Linux的服务器集群系统的研究与设计[J].电子科技,2012,25(6):4-5.

[4] 王恒亮.基于嵌入式Linux的Ext2根文件系统制作分析[J].电子科技,2015,28(1):114-115.

[5] 姚继锋.Linux 应用实例与技巧[M].北京:机械工业出版社,2001.

[6] 刘志强.基于项目的嵌入式Linux应用设计开发[M].北京:清华大学出版社,2010.

[7] 广州致远.嵌入式Linux开发教程[EB/OL].(2014-06-04) [2016-03-12]http://www.zlg.cn/ipc/down/down/id/92.html.

[8] 宋宝华.Linux设备驱动开发详解[M].北京:人民邮电出版社,2008.

[9] GENE S.Getting linux for your board[M].New York: Willy Press,2010.

[10] 刘刚.Linux系统移植[M].北京:清华大学出版社,2011.

[11] 么丽颖.Linux系统管理和应用[M].北京:中国铁道出版社,2011.

[12] Marcus E,Stern H.高可用性系统设计[M].汪青青,卢祖英,译.北京:清华大学出版社,2005.

[13] Matthew N,Stone R.Linux程序设计[M].2版.杨晓芸,译.北京:机械工业出版社,2002.

[14] 王险峰.Windows 环境下的多线程编程原理与应用[M].北京:清华大学出版社,2002.

[15] Daniel P Bovet.Understanding the Linux kernel[M].北京:中国电力出版社,2007.

[16] 孙天泽.嵌入式设计及Linux驱动开发指南[M].2版.北京:电子工业出版社,2007.

Based on Linux Multithreaded Management Analysis and Implementation

SUN Shuai, LI Chuanxi

(Nanjing Company,Aerospace Science and Industry Group (Shenzhen) Co. LTD.,Nanjing 211100,China)

Presents an effective prevent thread concurrent software design method of chaos and process abnormal end, comprehensive utilization of the POSIX Threads library system function, adjust the thread of the default configuration, reasonable planning thread structure and properly recycle the child thread. The practical test results show that the thread management strategy is a kind of correct multithreaded design method, and has high application value.

thread management;thread safety;thread priority;thread stack

2016- 11- 08

孙帅(1984-),男,硕士,工程师。研究方向:航天飞行控制计算机。李传玺(1980-),男,硕士,工程师。研究方向:航天电力仪器。

10.16180/j.cnki.issn1007-7820.2017.09.008

TP316.7

A

1007-7820(2017)09-027-03

猜你喜欢

掩码主线内核
多内核操作系统综述①
基于RISC-V的防御侧信道攻击AES软件实现方案
强化『高新』内核 打造农业『硅谷』
活化非遗文化 承启设计内核
人物报道的多维思考、主线聚焦与故事呈现
更加突出主线 落实四个到位 推动主题教育取得实实在在成效
低面积复杂度AES低熵掩码方案的研究
Linux内核mmap保护机制研究
基于布尔异或掩码转算术加法掩码的安全设计*
数字主线