




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Linux环境高级编程
李林
电子科技大学软件学院
第三讲线程的封装
李林
电子科技大学软件学院
・线程的基本概念
・线程的创建与终止II
・线程创建的封装111
.线程的同步
-线程创建的再封装
■Windows消息在Linux的重现
第二讲线程的封装
.线程的基本概念1111
・线程的创建与终止111
・线程创建的封装1,11
.线程的同步IIIII
-线程创建的再封装
■Windows消息在Linux的重现
—线程的概念_________
■进程的所有信息对该进程的所有线程都是
共享的,包括可执行的程序文本、程序的
I全局内存、堆内存、文件描述符等
■线程独有的:线程ID、寄存器值、栈、信
.号屏蔽字、errno值、线程私有数据
■典型的UNIX进程,可以看成是只有一个线
程的进程
5
—线程的概念_________
■同进程一样,每个线程也有一个线程ID
■进程ID在整个系统中是唯一的,但线程ID
不同,线程ID只在它所属的进程环境中有
।效一।।।।।।।।।
■线程ID的类型是pthread_t,在Linux中的定
义:
A在/usr/include/bits/pthreadtypes.h中
>typedefunsignedlongintpthread_t;
6
■pthread_self函数可以使调用线程获取自己
的线程后...........................
■函数原型IIIIIIII
#include<pthread.h>
pthread_tpthread_self();
■返回调用线程的线程ID
7
—线程的概念_________
■Linux中使用整型表示线程ID,而其他系统
则不一定
■FreeBSD5.2.1>MacOSX10.3用一个指
向pthread结构的指针来表示pthread_t类型。
■为了移植性,在比较两个线程ID是否相同
时,可以使用pthread_equal函数
8
pthreadequal^S
■该函数用于比较两个线程ID是否相同
■函数原型.....................11
#include<pthread.h>
intpthread_equal(pthread_ttid1,pthread_ttid2);
■若相等则返回非0值,否则返回0
9
・线程的基本概念
・线程的创建与终止11
・线程创建的封装111
.线程的同步
-线程创建的再封装
■Windows消息在Linux的重现
线程的创建与终止
■pthread_create函数
■pthread_exit函数
■pthread_join函数
■pthread_cancel函数
■pthread_detach函数
11
线程的创建与终止
■pthread_create函数
■pthread_exit函数
■pthread_join函数
■pthread_cancel函数
■pthread_detach函数
12
一线程的创建
■pthread_create函数用于创建一个线程
■函数原M..................................................
#include<pthread.h>
intpthread_create(pthread_t*restricttidp,
constpthread_attr_t*restrictattr,
void*(*start_rtn)(void*),
void*restrictarg);
■参数与返回值
>tidp:当pthread_create成功返回时,该函数将线程ID
存储在tidp指向的内存区域中
13
rest,jet关键字________
■restrict关键字C99标准引入的,
,.只能用于限定指针..................
B表明指针是访问一个数据对象的唯一且初始
的方式
resjcj;关键字________
intar[10];
int*restrictrestar=(int*)malloc(10*sizeof(int));
int*par=ar;
for(intn=0;n<10;n++){、
par[n]+=5;A
.restar[n]+=5;।'int*pnew=restar;
HB]i[[\_______________________?
ar[n]*=2;
par[n]+=3;
restar[n]+=3;
}
resjcj;关键字________
intar[10];
int*restrictrestar=(jnt*)malloc(10*sizeof(int));
int*par=ar;
for(intn=0;n<10;n++){/
par[n]+=5;~~/-------------\
『estar[n]+=5;::[int*吵(restar;
ar[n]*=2;/
par[n]+=3;
restar[n]+=3;
re&±rjet关键字
intar[10];
int*restrictrestar=(int*)malloc(1O*sizeof(int));
int*par=ar;
for(intn=0;n<10;n++){
par[n]+=5;
对restar的操作进行优化,
restar[n]+=8
restar[n]+=5;
无法对par的操作优化
Lr[n]*=2;]
par[n]+=8
I什么是编译单元?
par[n]+=3;
restar[n]+=3;
}
pthreadcrgate函数
■参数与返回值11111
0>attr:用于定制各种不同的线程属性,将在后
面部分讨论。通常可设为NULL,采用默认线
J呈扈性
>start_rtn:线程的入口函数,即新创建的线程
从该函数开始执行。该函数只有一个参数,即
arg,返回一个指针
>arg:作为start_rtn的第一个参数
A成功返回0,出错时返回各种错误码
18
线程的创建_________
■示例3.1
>编译:#g++test.cpp-Ipthread
»程序3.1没有任何输出。其原因在于主线程先
!!步新创建的线程退出।।।।।
*A什么是主线程?
■示例3.2
»如何能够等待线程的结束?pthreadjoin
19
线程的创建与终止
■pthread_create函数
■pthread_exit函数
■pthread_join函数
■pthread_cancel函数
■pthread_detach函数
20
一线程的终止
■单个线程的三种退出方式
A线程从启动例程中返回,返回值是线程的退出
II码IIIIIIIIII
।»线程被同一进程中的其他线程取消j।
>线程调用pthread_exit函数
21
pthreadexit函数
■该函数让线程退出1,1
#include<pthread.h>
voidpthread_exit(void*rval_ptr);
■参数
>rval_ptr:与线程的启动函数类似,该指针将
传递给pthread_join函数
22
线程的创建与终止
■pthread_create函数
■pthread_exit函数
■pthread_join函数
■pthread_cancel函数
■pthread_detach函数
23
=pjiirgadioin函数
■该函数用芋等,待某个线程终止1I
■函数原型.............................
#include<pthread.h>
intpthreadjoin(pthread_tthread,
void**rval_ptr);
■调用该函数的线程将一直阻塞,直到指定
的线程调用pthread_exit、从启动例程中返
回、被取消
24
PihjrgadJoin函数
intpthreadjoin(pthread_tthread,void**rval_ptr);
■返回值与参数
।A成功返回0,否则返回错误编号।||[]
>thread:需要等待的线程ID
>rval_ptr:
3■若线程从启动例程返回,rval_ptr将包含返回码1
■若线程由于pthread_exit终止,rval_ptr即pthread_exit的参数
■若线程被取消,由rval_pt「指定的内存单元就置为
PTHREAD_CANCELED
■若不关心线程返回值,可将该参数设置为NULL
25
PihjrgadJoin函数
■为什么pthread_join的第二个参数类型是指
针的指针?
I»指针的指针基本原理?传值与传指针的区别?
,>pthread_exit的一个目标是,把一个指针传递
给pthread」oin函数
Apthread」oin函数的思路是:通过参数的返回
值,将该指针值返回给pthread_join的调用者
»示州3.31।।।।।।।।
>示例3.4
26
线程的创建与终止
■pthread_create函数
■pthread_exit函数
■pthread_join函数
■pthread_cancel函数
■pthread_detach函数
27
□threadcancel函数
■线程调用该函数可以取消同一进程中的其
他线程,即让线程终止
■函数原型IIIIIIII
#include<pthread.h>
intpthread_cancel(pthread_ttid);
■参数与返回值
>tid:需要取消的线程ID
A成功返回0,出错返回错误编号
28
□threadcancel函数
■在默认情况下,pthread_cancel函数会使
得线程ID等于tid的线程,如同其调用了参
数为PTHREAD_CANCELED的
pthread_exit(示例3.5)
;■线程可以选择忽略取消方式或者控制取消
方式,将在后面讨论
■pthread_cancel并不等待线程终止,它仅
仅是提由请求
29
线程的创建与终止
■pthread_create函数
■pthread_exit函数
■pthread_join函数
■pthread_cancel函数
■pthread_detach函数
30
pthreaddetach函数
■在默认情况下,线程的终止状态会保存到
对该线程调用pthread_join
■若线程已经处于分离状态,线程的底层存
储资源可以在线程终止时立即被收回
■当线程被分离时,并不能用pthread_join函
数等待它的终止状态,止匕时pthread_join返
回EINVAL
■pthread_detach函数可以使线程进入分离
状态一
31
pthreaddetach函数
■函数原型I11,111♦
#include<pthread.h>
intpthread_detach(pthread_ttid);
■参数与返面值一
>tid:进入分离状态的线程的ID
A成功返回0,出错返回错误编号
■示例3.6
■若pthread_join比pthread_detach先调用,
也能获取到退出信息一
32
线程的创建与终止
■pthread_create函数
■pthread_exit函数
■pthread_join函数
■pthread_cancel函数
■pthread_detach函数
33
・线程的基本概念
・线程的创建与终止II
・线程创建的封装111
・线程的同步
-线程创建的再封装
■Windows消息在Linux的重现
线程创建的封装
■基于对象的封装
■面向对象的封装111
■基于模板的面向对象的封装
■基于接口的封装I11
■基于模板的面向方面的封装
■基于接口的再封装
基本对象的封装
■每次调用pthread_create很繁琐,能否简化
线程的创建工作......................
■示例3.7
>为什么使用static函数?................
|»为什么需要传递this指针?
>StartFunctionOfThread是private的,为什么能
司1够被调用?11,11,11
?A能否封装变化点?IIIIIII
36
面向对象的封装
■示例3.8
°X为什么析构是虚的?........................
।》能否封装变化点?............................
।»耦合度如何?।.........................
;下A如何理解继承关系耦合度高?
»耦合于接口、耦合于实现
*.♦■在3.8中,只能通过创建线程的方式执行业务逻辑
■若现在需要通过创建进程的方式执行业务逻辑,该
怎么办
基于模板的面向对象的封装
■示例3.9
A基于模板的静态多态................
>关键在于理清模板参数的演绎过程
基于接口的封装
■不同的线程,通常处理不同的事情,即业
务功能.......................
■如何对此变化点(执行不同业务功能)进
行封装
■示例3.10
■实现了线程具体业务功能的装配
接口的封装
■目前是以创建线程的方式执行业务功能,
如果需要创建进程的方式执行业务功能,
又当如何?
■如何对此变化点(创建不同的执行体)进
行封装?
■示例3.11
r实现了执行体的装配、业务功能的装配
■本课程的执行体创建模型,以3.11为基础
,但后续还有更多的改造
基于接口的封装
■基于接口的编程模式,更有利于装配
A在不改变处理类源代码的情况下,可以自由组
合
A继承是一种紧耦合的关系
.%■耦合于实现
■耦合于接口
»而基于接口的编程模式,仅耦合于接口
41
基于模板的面向方面的封装
■示例332...........................I
■为什么需要CLTypeSaver?
■为什么CLThread没有类模板参数?।।।
■当需要扩展时,即创建不同类型执行体,执行不
.同业务逻辑时,只需要新增加基类而不是派生类
■每个模板参数,即基类,代表一个方面।।
■创建线程还是进程,执行何种业务逻辑,甚至协
调器本身均可以装配
基于接口的再封装
■在3.10示例中,做到了不同执行体、不同
业务逻辑的装配,能否像3.12,做到协调
器的装配।..................
■创建完执行体之后,是否可以不立即执行
业务逻辑,这个流程能装配吗?
■示例3.13
・线程的基本概念
・线程的创建与终止II
・线程创建的封装111
.线程的同步
-线程创建的再封装
■Windows消息在Linux的重现
一线程的同步
■缓程向步加赧念.................I
、互斥量.............................
、读写锁.............................
■条件变量
45
线程同步的概念
,为什么需萋同'步.............I
A对同一个存储单元,至少存在两个执行体,其
一读该单元,另一写该单元,则需要同步,避
免不一致性
A在处理器架构中,对内存单元的修改,可能需
要多个总线周期,因此读操作和写操作有可能
交织在一起
46
线程同步的概念
■假设读操作需要
ThreadAThreadB
一个总线周期
■写操作需要两个read
总线周期
write3
■线程B和线程A冲time
突
write,
47
解决上述问题的方法
■使用锁,以保证共享ThreadAThreadB
存储一次只能被一个read
线程访问III
■说明获取、释放锁的
过程
read
48
线程同步的概念
ThreadAThreadBContentsofi
■通常,对一个存储
fetchiintoregister
单元的访问,要经5
(registet-5)
历三个步骤
incrementthe
contentsoffetchiintoregister
>将内存单元中的数5
theregister(register=5)
据,读入寄存器(register=6)
time
A对寄存器中的值进storethecontentsincrementthe
oftheregistercontentsof
6
行运算intoitheregister
(rcgister^6)(register06)
»将寄存器中的值,
storethecontents
写回内存单元oftheregister
intoi
■无锁时的情况(register=6)
49
线程同步的概念
■单线程的程序,需要对存储同步访问吗?
■若需要,能用锁的机制吗?
50
线程同步
■线程同步的概念
■互斥量II
■读写锁II
■条件变量
51
____________互斥量
■可以通过使用pthread的互斥接口保护数据,
1确保同一时间里只有q个线程访问数据I
■互斥量mutex,本质上就是一把锁11
I>在访问共享资源前,对互斥量进行加锁I
»在访问宛成耳释角互斥量上的四।।I
A对互斥量进行加锁后,任何其他试图再次对互
斥量加锁的线程将会被阻塞,直到锁被释放
52
互斥量的初始化
■互斥量在使用前,必须要对互斥量进行初始
化
,■函数原型................................
#include<pthread.h>
intpthread_mutex_init(pthread_mutex_t*mutex,
constpthread_mutexattr_t*attr);
■参数与返回值一一
>mutex:即互斥量,类型是pthread_mutex_t
1:1注意:mutex必须指向有效而内存区域
53
互斥量的初始化
intpthread_mutex_init(pthread_mutex_t*mutex,
constpthread_mutexattr_t*attr);
■参数与返回值....................I
>attr:设置互斥量的属性,通常可采用默认属性,
即可将attr设为NULL。后面再讨论互斥量的属性
»成功返回0,出错返回错误码
54
互斥量的销毁_________
■互斥量在使用完毕后,必须要对互斥量进行
销毁,以释放资源
,■函数原型.............................
#include<pthread.h>
intpthread_mutex_destroy(
pthread_mutex_t*mutex);
J参数与返回值一".
>mutex:即互斥量
A成功返回0,出错返回错误码
55
互斥量的加锁和解锁操作
■在对共享资源访问之前和访问之后,需要对
互斥量进行加锁和解锁操作
■「函数原型IIIIIIIII
#include<pthread.h>
intpthread_mutexjock(pthread_mutex_t*mutex);
Intpthread_mutex_unIock(
pthread_mutex_t*mutex);
■回忆锁的语义
56
尝试锁
■当使用pthread_mutex_lock时,若已被加锁,则
调用线程将被防塞。看殳有办法让线程不阻塞,
即实现非阻塞的语义।।।।।।
■函数景型1........................
#include<pthread.h>
intpthread_mutex_trylock(pthread_mutex_t*mutex);
・调用该函数时,若互斥量未加锁,则锁住该互斥
量,返回0;若互斥量已加锁,则函数直接返回
失败,即EBUSY
57
互斥量的操作顺序
■定义一个互斥量pthread_mutex_t
■调用pthread_mutexjnit初始化互斥量
■调用pthread_mutex_lock或者
pthread_mutex_tryplock对互斥量进行力口锁
慧操作I',"!1,।,,,
■调用pthread_mutex_unlock对互斥量解锁
・调用pthread_mutex_destroy车肖毁互斥量
■示例3.14(在示例3.11基础之上)
58
CLLOQ的改进
■2.27示例中,CLLog的实现不是线程安全
।的................................
।X写文件时的不安全।।।।।
>创建CLLog唯一对象时的不安全
a-示例3.25(在2.27基础之上)((
解决了写文件时的不安全问题,1
■示例3.26(在3.25基础之上)
>保证了多线程环境下只会创建一个对象
CLLOQ的改进________
■示例3.26存在的问题1111
ACLLog类型的对象只会被创建一次,其后都将
是读操作
1A但每次读都需要加锁、解锁,效率不高।
mA能否让后续的读操作,不再加锁
■示例427.........................................
"A双检测机制1111,111
>m_pLog为什么是volatile?
volatile变量
■volatile变量:一般在多线程中使用的比较
多
»例如有一个intx,有两个线程都要对其读写
»有些编译器或CPU会将x保存在寄存器中,读
的时候直接读取寄存器中的内容,而不是真实
的x在内存中的内容
A线程1,对X进行加1操作,止匕时内存中X的值为
2
A线程2想读X,结果从寄存器中读出1
»给变量加上volatile,指示程序每次读写变量都
必须从内存中读取,不要进行缓存(寄存器)
互斥量的封装_________
■每次使用互斥量都需要调用pthread_mutexjnit
和pthread_mutex_destroy卤数,能否简化
■示例3.15(在示例3.11基础之上)
互斥量的封装
■获取锁之后,一定要释放锁
■但是有时候锁的释放并不容易被控制1
■示例3.16(在示例3.11基础之上)
।»为什么主线程被阻塞?
»在mutex.Lock()和mutex_Unlock()之间若存在
复杂的函数调用,异常处理又当如何?
A每次访问临界区,都需要显示调用加锁和解锁,
能否简化
63
临界区的封装_________
■示例3.17(在示例3.11基础之上)
■无论是异常退出还是中途调用return退出,
'都能保证解锁।...................
■互斥量的不同范围,能提供不同程度的互
斥
’》类级别的(static的互斥量)
»对象级别的(普通数据成员的互斥量)
线程同步
,庚程向步加赧念111
’・亘斥量..............
■读写锁..............
■条件变量
65
___________________________
■读写锁与互斥量类似,不过读写锁允许更高的并
I行性..................................
■互斥量只有两种状态:锁住、不加锁
■读苛锁三种状态
1>读模'式下方口锁决态.........................
7写模式下加锁状态....................
I>不加]锁状申[]][]]I[
■一次只有一个线程可以占有写模式的读写锁、但
多个线程可以同时占用读模式的读写锁
66
________________
■当读写锁是写加锁状态时,解锁之前,所
有试图对这个锁加锁的线程都会被阻塞
■当读写锁是读加锁状态时,所有试图以读
模式对它进行加锁的线程,都可以得到访
问权,但以写模式进行加锁时,它必须阻
塞直到所有的线程释放读锁
■考虑:如何在互斥量的基础之上,实现单
写多读锁?
■示例3.18(在示例3.11基础之上)
67
读写锁API
■与互斥量一样,读写锁在使用之前,必须要初始
化;使用之后,必须要销毁iiii
■函数原型..................................
#include<pthread.h>
intpthread_rwlock_init(pthread_rwlock_t*rwlock,const
pthread_rwlockattr_t*attr);
intpthread_rwlock_destroy(pthread_rwlock_t*rwlock);
■返回值
A成功返回0,否则返回错误编号
68
读写锁API
intpthread_rwlock_init(pthread_rwlock_t
*rwlock,constpthread_rwlockattr_t*attr);
intpthread_rwlock_destroy(pthread_rwlock_t
*rwlock);
・参数'............................
>rwlock:读写锁
>attr:读写锁属性,若用默认属性,可设置为
NULLo将在后面讨论相关属性
69
pthreadFW!OQK1rdiock函数
■该函数用于锁定读锁1111
■函数原型.............................
#include<pthread.h>
intpthread_rwlock_rdlock(pthread_rwlock_t
*rwlock);
■参数与返回值
>rwlock:读写锁
»成功返回0,否则返回错误编号
70
pjh迨adrwlocj<wrlock函数
■该函数用于锁定写锁1111-
■函数原型.........................
#include<pthread.h>
intpthread_rwlock_wrlock(pthread_rwlock_t
*rwlock);
■参数与返回值
>rwlock:读写锁
»成功返回0,否则返回错误编号
71
□threadrwlockunlock函数
■该函数用于解除读锁或者写锁1'
■函数原型.........................
#include<pthread.h>
intpthread_rwlock_unlock(pthread_rwlock_t
*rwlock);
■参数与返回值
>rwlock:读写锁
»成功返回0,否则返回错误编号
72
一尝试读写锁函数
-该两个函数分别用于尝试获取读锁、写锁.
■函数原型..............................11
#include<pthread.h>
intpthread_rwlock_tryrdlock(pthread_rwlock_t*rwlock);
intpthread_rwlock_trywrlock(pthread_rwlock_t*rwlock);
■参数与返回值IIIIIII!
>rwlock:读写锁
A成功返回0,否则返回错误编号。可以获取锁时,函数
返回0;否则返回错误EBUSY
73
线程同步
,庚程向步加赧念111
’・亘斥量..............
■读写锁..............
■条件变量
74
■现有一需求,线程A先执行某操作后,线程
B才能执行另一操作,该如何实现?
■条件变量与互斥量一起使用时,允许线程
以无竞争的方式等待特定条件的发生
■与互斥量类似,条件变量也需要初始化和
销毁
75
条件变量的初始化和销毁
■函数原型
#include<pthread.h>
intpthread_cond_init(pthread_cond_t*cond,
pthread_condattr_t*attr);
intpthread_cond_destroy(pthread_cond_t*cond);
■参数和返回值।।।।।।।
>cond:条件变量
.>attr:条件变量属性,若为NULL,则使用默认属性
»成功返回0,出错返回错误编号
76
一等待条件的发生
■pthread_cond_wait函数将使调用线程进入阻塞
状态,直到条件为真
■函数原型
#include<pthread.h>
intpthread_cond_wait(pthread_cond_t*cond,
pthread_mutex_t*mutex);
■参数与返回值一一
>cond:条件变量
>mutex:互斥量
A成功返回0,否则返回错误编号
77
一等待条件的发生
■为什么pthread_cond_wait需要互斥量
»在调用pthread_cond_wait前,需要使互斥量
处于锁住状态
>这样pthread_cond_waitBi数,可以以原子的
方式,将调而线程放到等待条件的线程列表上
■pthread_cond_wait函数的特殊操作
»在线程阻塞前,调用pthread_mutex_unlock
BA在线程唤醒后,调用pthread_mutex_lock।
78
一等待条件的发生
■等待线程的操作顺序1111
»调用pthread_mutex_lock
»调用pthread_cond_wait
»调用pthread_mutex_unlock
79
一使等待的条件为真
■pthread_cond_signal和
pthread_cond_broadcast可以通知等待的线程,
条件已盔满足「j1
■pthread_cond_signal唤醒某一个等待该条件的
「线程r11111111
■pthread_cond_broadcast唤醒等待该条件的所
有线程——
80
—等待条件为真
,■函数原型...........................I
#include<pthread.h>
intpthread_cond_signal(pthread_cond_t*cond);
intpthread_cond_broadcast(pthread_cond_t*);
I-参金专返回值,,,,,,,
>cond:条件变量
A成功返回0,否则返回错误编号
条件变量的封装
■示例3.19(在示例3.11基础之上)
1a为什么主线程陷入阻塞状态而不返回?
>为什么子线程加入sleep后正常?
82
___________条件变量___________
-上例由错加原I因..............
»子线程调用pthread_cond_signal后,主线程才
调用pthread_cond_wait进入阻塞状态
,A这样,主线程就一直无法被唤醒।
■解决方案
A示例3.20(在示例3.11基础之上)
83
■等待线程
>调用pthread_mutex_lock
>While(判断条件)pthread_cond_wait
■重复检查条件是由于线程可能不是被pthread_cond_signal唤
醒,可能是由信号等唤醒(futex)
>pthread_mutex_unlock
■被等待线程一।।।।।।।
>调用pthread_mutex_lock
.>修改条件।一।7।।।।।।
>调用pthread_mutex_unlock
>调用pthread_mutex_broadcast等
84
___________条件变量___________
■P0SIX.1说明:pthread_cond_broadcast
等函数的调用无需考虑锢用线”是否拥有
锁,并建议在在lock和unlock以外的区域调
।用「用什么?।।।।।।।।
[假设率统|有J线中和।线岸2((((
矗A线程1获取mutex,在进行数据处理的时候,线
程2(等待线程)也想获取mutex,但是此时被
线程1所占用,线程2进入休眠,等待mutex被
释放
85
条件变量
A线程1做完数据处理后,调用
pthread_cond_signal唤醒等待队歹U中某个线程,
在本例币也就是线程2。线程1在调用
pthread_mutex_unlocklil,因为系统调度的原
因,线程2获取使用CPU的权利,那么它就想
要开始处理数据,但是在开始处理之前,
mutex必须被获取,线程1正在使用mutex,所
以线程2被迫再次进入休眠
»然后就是线程1执行pthread_mutex_unlock()
后,线程2方能被再次唤醒厂"
»十分低效
86
事件的封装__________
■条件变量的处理比较复杂,需要有flag变量、
1固定的函数调用序列等等।iiii
'能否简化条件变量的使用..............
■封装的思路:iI..................
>Windows的事件机制
:»让一个线程等待某一个事件的发生।।
■示例3.21(在示例3.11基础之上)
>为什么m_Flag是volatile的
87
一线程的同步
■缓程向步加赧念.................I
、互斥量.............................
、读写锁.............................
■条件变量
88
・线程的基本概念
・线程的创建与终止II
・线程创建的封装111
.线程的同步
I线程创建的再封装
■Windows消息在Linux的重现
线程创建的再封装
■一个CLThread类的对象,应该只对应一个
。线程.............................
■用户如果按照如下方式使用,会有什么后
果?
CLThread*p=..................;
p->Run();
p->Run();
线程创建的再封装
■前一次创建的线程,可能无法再被控制。
例如:m_ThreadlD仅为刚创建线程的ID,
调用WsdtForDeath,将无法等待上一个线
程的结束।।।।।।।।
■如何解决,以防止在一个CLThread对象上
,多次调用Run方法?一‘||
■示例3.22(在示例3.11基础之上)
线程创建的再封装
■通常情况下,CLThread类及
CLExecutiveFunctionProvider派生类的对
象,应从堆中分配。为什么不是栈上?
■从堆中分配,就需要显式的释放,能否简
化?能否让类的使用者,只分配对象,而
不用调用delete?
■示例3.23(在示例3.22基础之上)
线程创建的再封装
■在有些情况下,新线程的创建者,可能不
需要等待新线程死亡,即不调用
WaitForDeath
■这样3.23的释放对象方式将失效।।।
■示例3.24(在示例3.23基础之上)
»增加一个标识,让用户指定他是否需要等待新
线程死亡
线程创建的再封装
1
■产生异常的原因在于:111'V
>新线程在主线程调用WaitForDeath之前就已经退出了
>甚至有可能在主线程刚调用完pthread_create之后,
就退出了
■解决办法:।।।।।।।।।
>需要保证在Run方法退出之前,新线程不会死亡
A若用户选择了不等待新线程死亡,则他就不应该再调
fflWaitForDeath
»另外,从语义上讲,Run方法返回前,应保证新线程
确实已经被创建了
A示例3.28(在示例3.24基础之上)
・线程的基本概念
・线程的创建与终止II
・线程创建的封装111
.线程的同步
g线程创建的再封装
■Windows消息在Linux的重现
Windows消息在Linux的重现
■在windows中,进行线程之间的通信十分
简便。Windows系统为每个线程都配备了
二个消息队列..................
■调用PostThreadMessage函数,可以向一
1个线程发送消息।।।।।।
■调用GetMessage函数,可以从消息队列中
获取一个消息
生产者/消费者模型
■消息队列及机制,是一种典型的生产者/消
费者模型应用。
■发送消息的线程(生产者):将消息投入
到消息队列后,即返回
■消息的接收线程(消费者):一直处于阻
塞等待状态,直到有线程将消息投入到消
息队列中
■我们的目标:建立一个自定义的消息队列
,以实现同一进程内线程之间的通信
Windows消息在Linux的重现
■梏息的封装111111-
■自定义消息队列的实现1,11
■消息循环机制的封装11111
■创建线程与消息循环的结合III
■简单的名字服务..................
■使用的简化
Windows消息在Linux的重现
■消息的封装.....................♦
■自定义消息队列的实现1,11
■消息循环机制的封装..............
■创建线程与消息循环的结合,11
■简单的名字服务..................
■使用的简化
消息的封装__________
■Windows的线程消息:
BOOLWINAPIPostThreadMessage(
DWORDidThread,
UINTMsg,
WPARAMwParam,
LPARAMIParam
);
■Windows的消息包含了线程ID,以及两个自定义
参数,不符合面向对象的思想
■需要建立起有关消息的继承体系
消息的继承体系
■示例3.29
■CLMessage是对消息的抽象,仅包含了消
息的ID
■线程之间发送的具体消息,需要从।।
CLMessage派生,并定义属于该消息自己
的参数
Windows消息在Linux的重现
■消息的封装111111-
■自定义消息队列的实现||||
■消息循环机制的封装..............
■创建线程与消息循环的结合111
■简单的名字服务..................
■使用的简化
自定义消息队列的实现
■队列本身采用STL库中的queue类,该类型
的队列能自动增长................
■必须以线程安全的方式,将消息放入到队
列中,然后通知等待的线程消息已到达
■通知的机制可以采用CLEvent类,但3.21
示例中的CLEvent必须改造
■示例3.30
自定义消息队列的实现
■CLMessageQueue的实现
■示例3.31
■在上例中,采用STL的queue实现了消息队
歹U]।।।।।।।।।।
■也可以采用其他方式实现,例如管道、网
络通信、自定义的队列等等
■如何封装这一变化点?它们之间是否有共
通的部分(均为生产者/消费者模型应用)
Windows消息在Linux的重现
■消息的封装111111-
■自定义消息队列的实现||||
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 砼构件的施工质量评定方法考核试卷
- 生态保护与可持续发展考核试卷
- 2025年证券从业资格考试高效学习规划试题及答案
- 稀有金属加工中的企业品牌建设与市场推广考核试卷
- 2025年企业审计新规范的实施与影响试题及答案
- 2025年审计程序优化试题及答案
- 火车站票务系统优化考核试卷
- 管道工程质量管理案例分析考核试卷
- 2025年产业链上下游关系分析试题及答案
- 2024微生物检验技师考试的准备工作试题及答案
- 跨越学习高原期-高中心理健康主题班会
- 博物馆藏品库房管理课件
- 电梯井内脚手架搭拆施工专项方案
- 涉外商标实务培训课件
- 2022年2月兴业银行审计部招聘人员模拟试题3套(含答案解析)
- 社会研究方法复习资料(风笑天版)
- 《青年友谊圆舞曲》音乐课件
- 博士后出站研究报告
- 中华人民共和国海关进出境自用物品申请表
- 高一语文《赤壁赋》 完整版课件PPT
- 纸包装生产企业设备管理课件
评论
0/150
提交评论