[发明专利]一种基于多线程编程及消息队列的多线程并行处理方法有效

专利信息
申请号: 201210316211.7 申请日: 2012-08-31
公开(公告)号: CN102902512A 公开(公告)日: 2013-01-30
发明(设计)人: 吴庆;张清;赵开勇 申请(专利权)人: 浪潮电子信息产业股份有限公司
主分类号: G06F9/38 分类号: G06F9/38
代理公司: 暂无信息 代理人: 暂无信息
地址: 250014 山东*** 国省代码: 山东;37
权利要求书: 查看更多 说明书: 查看更多
摘要:
搜索关键词: 一种 基于 多线程 编程 消息 队列 并行 处理 方法
【权利要求书】:

1.一种基于多线程编程及消息队列的多线程并行处理方法,其特征在于在单节点内,创建三类pthread线程,分别为读、计算、写线程,并且各类线程数目灵活可配置,开辟多缓存,创建四个队列,用于线程间通信,调配计算任务及管理缓存空间资源,具体步骤如下:

基于多缓冲和消息队列建立任务分发机制,包括:

1)计算任务的划分:任务划分的基本单位总的计算任务数是TOTAL_JOB,它可以被划分成多个子任务,定义每个子任务大小为JOB_SIZE,定义灵活的任务划分策略,软件有自动配置模式和用户手动配置模式;

2)任务分发、执行策略,包括:

(1)子任务实际由读线程来生成;读线程定义每个子任务的信息tmp_msg,包括:job_begin,job_size,buf_id;

其中:job_begin是该任务计数编号,通过它可以确定该任务的起始LINE号和CMP号;

job_size定义了该任务的大小,其上限是预先已经定义好的JOB_SIZE;

buf_id指明了该任务所在的BUF编号;

(2)任务信息tmp_msg的类型实际上就是消息队列成员的类型,被加入到各个队列中;

3)子任务执行所需资源的竞争策略完成一个子任务,需要如下几个步骤:

读线程根据当前读取进度CURRENT_READ_STEP及总作业大TOTAL_STEP,确定当前任务的起始job_begin,任务大小job_size,并且从空SR_BUF队列SR_BUF_EMPTY_QUEUE中获取一个空的SR_BUF_ID,将数据读入SR_BUF_ID对应的SR_BUF中,即SR_BUF[SR_BUF_ID],然后将新生成的任务信息保存至tmp_msg中,并将tmp_msg加入新计算任务队列SR_BUF_FULL_QUEUE中;

计算线程需先从新计算任务队列SR_BUF_FULL_QUEUE中获取一个新计算任务,然后再从空闲目标缓冲队列DR_BUF_EMPTY_QUEUE中获取一个空闲DR_BUF_ID,之后才进行计算,计算源数据为SR_BUF[SR_ BUF_ID],计算结果存放于DR_BUF[DR_BUF_ID]中,计算结束后,释放SR_BUF_ID对应的源数据缓存,即将SR_BUF_ID加入SR_BUF_EMPTY_QUEUE队列中,并告知写线程进行输出,即将tmp_msg加入到待输出队列DR_BUF_FULL_QUEUE中;

写线程从待输出任务队列DR_BUF_FULL_QUEUE中获取一个写任务信息tmp_msg,该任务信息定义了数据存放的DR_BUF_ID以及该写任务需要写到的位置信息,即job_begin,以及写任务的规模job_size,写线程完成该输出任务后,需要告知计算线程DR_BUF[DR_BUF_ID]中的数据已经输出完毕,可重新用于存放计算结果, 即将DR_BUF_ID加入DR_BUF_EMPTY_QUEUE队列中;

多缓冲设计

设计多个源数据缓冲SR_BUF和目标数据缓冲DR_BUF,缓冲的数目灵活可调,为了以最少的缓冲达到最高的效能,缓冲的个数有一个临限值,理论上,源缓冲与目标缓冲的数目至少为计算线程数的2倍,即:

SR_BUF_NUM>=2*COMPUTE_THREAD_NUM,DR_BUF_NUM>= 2*COMPUTE_THREAD_NUM

考虑到实际生产中网络资源的竟争和不稳定因素,保证计算线程随时都能获得一个源缓冲和一个目标缓冲,软件为每个计算线程预留一个缓冲余量,默认将源数据缓冲和目标缓冲数都设置为计算线程数的3倍;

环形消息队列设计

为了实现上述任务分发策略,设计以下四个队列:

消息队列生产者消费者初始状态备注SR_BUF_EMPTY_QUEUECOMPUTE_threadREAD_threadSR_BUF_ID全部入队空SR_BUF队列SR_BUF_FULL_QUEUEREAD_threadCOMPUTE_thread满SR_BUF队列DR_BUF_EMPTY_QUEUEWRITE_threadCOMPUTE_threadDR_BUF_ID全部入队空DR_BUF队列DR_BUF_FULL_QUEUECOMPUTE_threadWRITE_thread满DR_BUF队列

其中消息队列中存放的消息数据类型定义如下:

SR_BUF_FULL_QUEUE:新的计算任务队列新计算任务消息队列,记录作业信息JOB_INFO(包括JOB_BEGIN,JOB_SIZE,SR_BUF_ID),由读线程写入(生产),计算线程弹出(消费)当读线程向SR_BUF_ID读入新数据时,将JOB_INFO入队,计算线程弹出JOB_INFO时,计算SR_BUF_ID对应的源数据;

SR_BUF_EMPTY_QUEUE: 存放当前空闲SR_BUF_ID号源缓冲释放消息队列,与SR_BUF_FULL_QUEUE功能相反,由计算线程写入,读线程弹出,当SR_BUF_ID对应的任务计算完毕时,释放SR_BUF_ID,告知读线程可对其更新数据;

DR_BUF_EMPTY_QUEUE: 存放当前空闲DR_BUF_ID号目标缓冲为空消息队列,记录DR_BUF_ID号,由写线程写入,计算线程弹出;

当写线程对DR_BUF_ID数据输出完毕时,将DR_BUF_ID入队,告知计算线程,该DR_BUF_ID输出完毕可重新用于计算,计算线程弹出DR_BUF_ID时,启动计算,并将结果写入DR_BUF_ID对应的目标缓冲中;

DR_BUF_FULL_QUEUE: 新的写任务队列新写任务消息队列,记录作业信息JOB_INFO,包括JOB_BEGIN,JOB_SIZE,DR_BUF_ID,由计算线程写入,写线程弹出;

当计算线程向DR_BUF_ID读入新数据时,将JOB_INFO入队,写线程弹出JOB_INFO时,对DR_BUF_ID对应的目标数据进行输出;

线程设计

1)主线程设计

(1)主线程功能及运行流程如下:

1.参数预处理;

2.定义读、计算、写线程数;

3.定义源、目标缓存数目,与计算线程数相关;

4.定义任务划分粒度,即子任务规模JOB_SIZE;

5.开辟源、目标缓冲内存空间;

6.创建并初始化消息队列、锁、信号量;

创建并启动读、计算、写线程;

8.等待所有线程退出;

9.其它处理;

10程序退出;

(2)线程伪代码

1.INIT(PARA);

2.SET(THREAD_NUM);

3.SET(BUF_NUM);

4.SET(JOB_SIZE)

5.CREATE(OUTPUT_FILE_LIST);

6.MALLOC(BUF);

7.INIT(QUEUE);

8.INIT(MUTEX);

9.INIT(SEM);

10.INIT(PROGRESS,Total_Step);

11.CREATE(THREADS);

12.WHILE State_Flag && !wasCancelled && progress<=Total_Step

13.IF PROGRESSS.wasCancelled()

14.wasCancelled=true;

15.break;

16.ENDIF

17.IF ! State_Flag

18.breadk

19.ENDIF

20.SEM_WAIT(progress_sm);

21.progress+=JOB_SIZE;

22.SET_PROGRESS(progress);

23.DONE

24.JOIN(THREADS);

25.IF State_Flag && !wasCancelled

26.CREATESEIS_INDEX(OUTPUT_FILE_LIST);

27.ELSE

28.DELETESEIS_OBJ(OUTPUT_FILE_LIST);

29.ERROR_PROCESS();

30.EXIT

31.ENDIF

32.DELETE(PROGRESS);

33.DELETE( BUF);

34.DESTROY(MUTEX);

35.DESTROY(SEM);

36.PRINTF(LOG);

37.EXIT;

2)读线程设计

(1)线程数设计

根据实际应用需求,灵活设置读线程数,默认只设置一个读线程;

(2)线程功能及运行流程

1.参数初始化;

2.检查错误标志及用户行为,如果出错或被用户取消,则进入步骤9,否则进入步聚3;

3.检查当前任务进度READ_CURRENT_STEP,判断是否完成所有读任务,如果是,则进入步骤9,否则进入步聚4;

4.根据当前读进度READ_CURRENT_STEP和总任务数Total_Step,计算剩余任务数left_job,生成新任务起始job_begin及大小信息Job_size,job_size上限为JOB_SIZE,更新任务计数READ_CURRENT_STEP;

5.从SR_BUF_EMPTY_QUEUE队列中获得一个空闲SR_BUF_ID;

6.从源文件INPUT_FILE中读取任务源数据至源数据缓存SR_BUF[SR_BUF_ID]中;

7.将该任务信息tmp_msg加入新计算任务队列SR_BUF_FULL_QUEUE中;

8.返回步骤2;

9.线程退出;

3)线程伪代码

1.INIT

2.WHILE State_Flag && !wasCancelled

3.IF READ_CURRENT_STEP <= Total_Step

4.job_begin=READ_CURRENT_STEP;

5.job_left=Total_Step-READ_CURRENT_STEP;

6.IF job_left>JOB_SIZE

7.job_size=JOB_SIZE;

8.ELSE

9.job_size=job_left;

10.READ_CURRENT_STEP += job_size;

11.tmp_msg = SR_BUF_EMPTY_QUEUE.pop();

12.SR_BUF_id=tmp_msg.buf_id;

13.READ(INPUT_FILE,SR_BUF[SR_BUF_id])

14.tmp_msg(job_begin,job_size,SR_BUF_id);

15.SR_BUF_FULL_QUEUE.push(tmp_msg);

16.ELSE

17.pthread_exit();

18.ENDIF 

19.DONE

20.pthread_exit();

4)计算线程设计

线程数设计:

默认情况下,计算线程数为系统可用CPU核数,即SYS_CPU_CORE_NUM,用户通过宏COMPUTE_THREAD_NUM来定义计算线程数;

线程功能及运行流程:

1.参数初始化;

2.检查错误标志及用户行为,如果出错或被用户取消,则进入步聚10,否则进入步聚3;

3.检查当前任务进度COMPUTE_CURRENT_STEP,判断是否完成所有读任务,如果是,则进入步骤10,否则进入步聚4;

4.从新计算任务队列SR_BUF_FULL_QUEUE中获取一个任务信息tmp_msg,其包含了任务的起始信息job_begin,大小信息job_size,以及任务数据存放源缓冲编号SR_BUF_ID,并更新任务计数COMPUTE_CURRENT_STEP;

5.从DR_BUF_EMPTY_QUEUE队列中获得一个空闲的DR_BUF_ID;

6.以SR_BUF[SR_BUF_ID]为数据输入缓存,以DR_BUF[DR_BUF_ID]为数据输出缓存进行计算;

7.将SR_BUF_ID加入SR_BUF_EMPTY_QUEUE中,表示SR_BUF[SR_BUF_ID]所存的数据计算完毕,需要重新加载源数据;

8.根据计算任务信息,生成写任务信息,并将其加入到DR_BUF_FULL_QUEUE队列中,表示需要写线程进行输出;

9.返回步骤2;

10.线程退出;

线程伪代码

1)INIT

2)WHILE State_Flag && !wasCancelled

3)IF COMPUTE_CURRENT_STEP <= Total_Step

4)tmp_msg=SR_BUF_FULL_QUEUE.pop()

5)job_begin=tmp_msg.job_begin;

6)job_size=tmp_msg.job_size;

7)SR_BUF_id =tmp_msg.buf_id;

8)COMPUTE_CURRENT_STEP+=job_size;

9)tmp_msg= DR_BUF_EMPTY_QUEUE.pop();

10) DR_BUF_id =tmp_msg.buf_id;

11)COMPUTE(INPUT_FILE,SR_BUF[SR_BUF_id],DR_BUF[DR_BUF_id])

12)tmp_msg(-1,-1,SR_BUF_id);

13) SR_BUF_EMPTY_QUEUE.push(tmp_msg);

14) tmp_msg(job_begin,job_size,DR_BUF_id);

15) DR_BUF_FULL_QUEUE.push(tmp_msg);

16) ELSE

17) pthread_exit();

18)ENDIF 

19)DONE

20)pthread_exit();

4)写线程设计

(1)线程数设计

根据实际应用需求,灵活设置写线程数,默认只设置一个写线程;

(2)线程功能及运行流程

1.参数初始化;

2.检查错误标志及用户行为,如果出错或被用户取消,则进入步骤9,否则进入步聚3;

3.检查当前任务进度WRITE_CURRENT_STEP,判断是否完成所有读任务,如果是,则进入步骤9,否则进入步聚4;

4.从新写任务队列DR_BUF_FULL_QUEUE中获取一个写任务信息tmp_msg,其包含了任务的起始信息job_begin,大小信息job_size,以及任务数据存放目标缓冲编号DR_BUF_ID,并更新任务计数WRITE_CURRENT_STEP;

5.将目标缓存DR_BUF[DR_BUF_ID]中的数据输出至OUTPUT_FILE;

6.将DR_BUF_ID加入DR_BUF_EMPTY_QUEUE中,表示DR_BUF[DR_BUF_ID]所存的数据输出完毕,需要重新加载计算结果;

7.向主线程发送更新进度条信号;

8.返回步骤2;

9.线程退出;

(4)线程伪代码

1.INIT

2.WHILE State_Flag && !wasCancelled

3.IF WRITE_CURRENT_STEP <= Total_Step

4.tmp_msg = DR_BUF_FULL_QUEUE.pop();

5.job_begin=tmp_msg.job_begin;

6.job_size=tmp_msg.job_size;

7.DR_BUF_id=tmp_msg.buf_id;

8.WRITE_CURRENT_STEP+=job_size;

9.WRITE(OUTPUT_FILE,DR_BUF[DR_BUF_id])

10.tmp_msg(-1,-1,DR_BUF_id);

11.DR_BUF_EMPTY_QUEUE.push(tmp_msg);

12.SEM_POST (progress_sem);

13.ELSE

14.pthread_exit();

15.ENDIF 

16.DONE

17.pthread_exit()。

下载完整专利技术内容需要扣除积分,VIP会员可以免费下载。

该专利技术资料仅供研究查看技术是否侵权等信息,商用须获得专利权人授权。该专利全部权利属于浪潮电子信息产业股份有限公司,未经浪潮电子信息产业股份有限公司许可,擅自商用是侵权行为。如果您想购买此专利、获得商业授权和技术合作,请联系【客服

本文链接:http://www.vipzhuanli.com/pat/books/201210316211.7/1.html,转载请声明来源钻瓜专利网。

×

专利文献下载

说明:

1、专利原文基于中国国家知识产权局专利说明书;

2、支持发明专利 、实用新型专利、外观设计专利(升级中);

3、专利数据每周两次同步更新,支持Adobe PDF格式;

4、内容包括专利技术的结构示意图流程工艺图技术构造图

5、已全新升级为极速版,下载速度显著提升!欢迎使用!

请您登陆后,进行下载,点击【登陆】 【注册】

关于我们 寻求报道 投稿须知 广告合作 版权声明 网站地图 友情链接 企业标识 联系我们

钻瓜专利网在线咨询

周一至周五 9:00-18:00

咨询在线客服咨询在线客服
tel code back_top