POSIX线程程序设计中文版全解Word文档下载推荐.docx
- 文档编号:20758137
- 上传时间:2023-01-25
- 格式:DOCX
- 页数:37
- 大小:636.88KB
POSIX线程程序设计中文版全解Word文档下载推荐.docx
《POSIX线程程序设计中文版全解Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《POSIX线程程序设计中文版全解Word文档下载推荐.docx(37页珍藏版)》请在冰豆网上搜索。
可以被操作系统调度的独立的指令流。
但是这
是什么意思呢?
•对于软件开发者,在主程序中运行的“函数过程”可以很好的描述线程的概念。
•进一步,想象下主程序(a.out)包含了许多函数,操作系统可以调度这些
函数,使之同时或者(和)独立的执行。
这就描述了“多线程”程序。
*怎样完成的呢?
・在理解线程之前,应先对UNIX进程(process有所了解。
进程被操作系统创建,需要相当多的“额外开销”。
进程包含了程序的资源和执行状态信息。
如下:
o进程ID,进程groupID,用户ID和groupID
o环境o工作目录o程序指令
o寄存器
o栈
o堆
o文件描述符
o信号动作(Signalactions
o共享库
o进程间通信工具(如:
消息队列,管道,信号量或共享内存)
UNIXPROCESSTHREADSWITHINAUNIX
PROCESS
•线程使用并存在于进程资源中,还可以被操作系统调用并独立地运行,这主要是因为线程仅仅复制必要的资源以使自己得以存在并执行。
•独立的控制流得以实现是因为线程维持着自己的:
o堆栈指针
o调度属性(如:
策略或优先级)
o待定的和阻塞的信号集合(Setofpendingandblockedsigna)
o线程专用数据(TSD:
ThreadSpecificData.)
*因此,在UNIX环境下线程:
o存在于进程,使用进程资源
o拥有自己独立的控制流,只要父进程存在并且操作系统支持
o只复制必可以使得独立调度的必要资源
o可以和其他线程独立(或非独立的)地共享进程资源
o当父进程结束时结束,或者相关类似的
o是“轻型的”,因为大部分额外开销已经在进程创建时完成了
•因为在同一个进程中的线程共享资源:
o一个线程对系统资源(如关闭一个文件)的改变对所有其它线程是可以见的
o两个同样值的指针指向相同的数据
o读写同一个内存位置是可能的,因此需要成员显式地使用同步
什么是Pthreads?
•历史上,硬件销售商实现了私有版本的多线程库。
这些实现在本质上各自
不同,使得程序员难于开发可移植的应用程序。
•为了使用线程所提供的强大优点,需要一个标准的程序接口。
对于UNIX
系统,IEEEPOSIX1003.1c(1995)标准制订了这一标准接口。
依赖于该标准的实现就称为POSIXthreads或者Pthreads现在多数硬件销售商也提供Pthreads附加于私有的API。
*Pthreads被定义为一些C语言类型和函数调用,用pthread.h头(包含)文件和线程库实现。
这个库可以是其它库的一部分,如libc。
为什么使用Pthreads?
•使用Pthreads的主要动机是提高潜在程序的性能。
•当与创建和管理进程的花费相比,线程可以使用操作系统较少的开销,管理线程需要较少的系统资源。
例如,下表比较了fork()函数和pthread_create(函数所用的时间。
计时反应了50,000个进程/线程的创建,使用时间工具实现,单位是秒,没有优化标志。
备注:
不要期待系统和用户时间加起来就是真实时间,因为这些SMP系
统有多个CPU同时工作。
这些都是近似值。
—
平台
fork()
pthread_create()
real
user
sys
AMD2.4GHzOpteron(8cpus/node)
41.07
60.08
9.01
0.66
0.19
0.43
IBM1.9GHzPOWER5p5-575(8cpus/node)
64.24
30.78
27.68
1.75
0.69
1.10
IBM1.5GHzPOWER4
104.05
48.64
47.21
2.01
1.00
1.52
(8cpus/node)
0.90
INTEL2.4GHzXeon(2cpus/node)
54.95
1.54
20.78
1.64
0.67
INTEL1.4GHzItanium2(4cpus/node)
54.54
1.07
22.22
2.03
1.26
、Source
fork_vs_thread.txt
•在同一个进程中的所有线程共享同样的地址空间。
较于进程间的通信,在
许多情况下线程间的通信效率比较高,且易于使用。
•较于没有使用线程的程序,使用线程的应用程序有潜在的性能增益和实际的优点:
oCPU使用I/O交叠工作:
例如,一个程序可能有一个需要较长时间的I/O操作,当一个线程等待I/O系统调用完成时,CPU可以被其它线程使用。
o优先/实时调度:
比较重要的任务可以被调度,替换或者中断较低优先级的任务。
o异步事件处理:
频率和持续时间不确定的任务可以交错。
例如,web服务器可以同时为前一个请求传输数据和管理新请求。
•考虑在SMP架构上使用Pthreads的主要动机是获的最优的性能。
特别的,如果一个程序使用MPI在节点通信,使用Pthreads可以使得节点数据传输得到显著提高。
•例如:
oMPI库经常用共享内存实现节点任务通信,这至少需要一次内存复制操作(进程到进程)。
oPthreads没有中间的内存复制,因为线程和一个进程共享同样的地址空间。
没有数据传输。
变成cache-to-CPU或memory-to-CPU的带宽(最坏情况),速度是相当的快。
o比较如下:
Platform
MPISharedMemoryBandwidth(GB/sec)
PthreadsWorstCaseMemory-to-CPUBandwidth(GB/sec)
AMD2.4GHz
Opteron
1.2
5.3
IBM1.9GHzPOWER5p5-575
4.1
16
IBM1.5GHz
POWER4
2.1
4
Intel1.4GHz
Xeon
0.3
4.3
Itanium2
1.8
6.4
使用线程设计程序
|并行编程:
•在现代多CPU机器上,pthread非常适于并行编程。
可以用于并行程序设计的,也可以用于pthread程序设计。
•并行程序要考虑许多,如下:
o用什么并行程序设计模型?
o问题划分
o加载平衡(Loadbalancing)
o通信
o数据依赖
o同步和竞争条件
o内存问题
oI/O问题
o程序复杂度
o程序员的努力/花费/时间
o・・・
•包含这些主题超出本教程的范围,有兴趣的读者可以快速浏览下
“IntroductiontoParallelComputing”教程。
*大体上,为了使用Pthreads的优点,必须将任务组织程离散的,独立的,可以并发执行的。
例如,如果routine1和routine2可以互换,相互交叉和(或者)重叠,他们就可以线程化。
routinel
routing
finalroutine
finalroutine"
I
■
■
•拥有下述特性的程序可以使用pthreads
o工作可以被多个任务同时执行,或者数据可以同时被多个任务操作。
o阻塞与潜在的长时间I/O等待。
o在某些地方使用很多CPU循环而其他地方没有。
o对异步事件必须响应。
o一些工作比其他的重要(优先级中断)。
•Pthreads也可以用于串行程序,模拟并行执行。
很好例子就是经典的web浏览器,对于多数人,运行于单CPU的桌面/膝上机器,许多东西可以同时“显示”出来。
•使用线程编程的几种常见模型:
o管理者/工作者(Manager/worker):
—个单线程,作为管理器将工作分配给其它线程(工作者),典型的,管理器处理所有输入和分配工作给其它任务。
至少两种形式的manager/worker模型比较常用:
静态worker池和动态worker池。
o管道(Pipeline):
任务可以被划分为一系列子操作,每一个被串行处理,但是不同的线程并发处理。
汽车装配线可以很好的描述这个模型。
oPeer:
和manager/worker模型相似,但是主线程在创建了其它线程后,自己也参与工作。
卜共享内存模型(SharedMemoryModel):
*所有线程可以访问全局,共享内存
*线程也有自己私有的数据
*程序员负责对全局共享数据的同步存取(保护)
I线程安全(Thread-safeness):
•线程安全:
简短的说,指程序可以同时执行多个线程却不会“破坏“共享数据或者产生“竞争”条件的能力。
*例如:
假设你的程序创建了几个线程,每一个调用相同的库函数:
o这个库函数存取/修改了一个全局结构或内存中的位置。
o当每个线程调用这个函数时,可能同时去修改这个全局结构活内存位置。
o如果函数没有使用同步机制去阻止数据破坏,这时,就不是线程安
全的了。
subA
・如果你不是100%确定外部库函数是线程安全的,自己负责所可能引发的问题。
・建议:
小心使用库或者对象,当不能明确确定是否是线程安全的。
若有疑虑,假设其不是线程安全的直到得以证明。
可以通过不断地使用不确定的函数找出问题所在。
PthreadsAPI
•PthreadsAPI在ANSI/IEEEPOSIX1003.1T995标准中定义。
不像MPI,该标准不是免费的,必须向IEEE购买。
•PthreadsAPI中的函数可以非正式的划分为三大类:
1.线程管理(Threadmanagement:
第一类函数直接用于线程:
创建(creating),分离(detaching),连接(joining)等等。
包含了用于设置和查询线程属性(可连接,调度属性等)的函数。
2.互斥量(MutexeS:
第二类函数是用于线程同步的,称为互斥量
(mutexe9,是"
mutualexclusion"
的缩写。
Mutex函数提供了创建,销毁,锁定和解锁互斥量的功能。
同时还包括了一些用于设定或修改互斥量属性的函数。
3.条件变量(Conditionvariables:
第三类函数处理共享一个互斥量的线程间的通信,基于程序员指定的条件。
这类函数包括指定的条件变量的创建,销毁,等待和受信(signal)。
设置查询条件变量属性的函数也包含其中。
«
命名约定:
线程库中的所有标识符都以pthread开头
RoutinePrefix
FunctionalGroup
pthread_
线程本身和各种相关函数
pthread_attr_
线程属性对象
pthread_mutex_
互斥量
pthread_mutexattr_
互斥量属性对象
pthread_cond_
条件变量
pthread_condattr_
条件变量属性对象
pthread_key_
线程数据键(Thread-specificdatakeys
•在API的设计中充满了不透明对象的概念,基本调用可以创建或修改不透明对象。
不透明的对象可以被一些属性函数调用修改。
•PthreadAPI包含了60多个函数。
该教程仅限于一部分(对于刚开始学习Pthread的程序是非常有用的)。
*为了可移植性,使用Pthread库时,pthread.h头文件必须在每个源文件中包含。
・现行POSIX标准仅定义了C语言的使用。
Fortran程序员可以嵌入C函数调用使用,有些Fortran编译器(像IBMAIXFortran)可能提供了FortranpthreadsAPI。
*关于Pthreads有些比较优秀的书籍。
其中一些在该教程的参考一节列出。
编译多线程程序
•下表列出了一些编译使用了pthreads库程序的命令:
Compiler/Platform
CompilerCommand
Description
IBM
AIX
xlc_r/cc_r
C(ANSI/non-ANSI)
xlC_r
C++
xlf_r-qnosavexlf90_r-qnosave
Fortran-usingIBM'
sPthreadsAPI(non-portable)
INTELLinux
icc-pthread
C
icpc-pthread
1
PathScale
pathcc-pthread
Linux
pathCC-pthread
PGI
pgcc-lpthread
Linux
pgCC-lpthread
GNU
gcc-pthread
GNUC
Linux,AIX
g++-pthread
GNUC++
线程管理(ThreadManagement)
创建和结束线程
I函数:
I
pthreadcreate(thread,attr,start_routine,arg)pthread_exit(status)
pthread_attr_init(attr)
pthread_attr_destroy(attr)
I创建线程:
•最初,main函数包含了一个缺省的线程。
其它线程则需要程序员显式地创建。
*pthread_create创建一个新线程并使之运行起来。
该函数可以在程序的任何地方调用。
*pthread_create参数:
othread:
返回一个不透明的,唯一的新线程标识符。
oattr:
不透明的线程属性对象。
可以指定一个线程属性对象,或者NULL为缺省值。
ostart_routine:
线程将会执行一次的C函数。
oarg:
传递给start_routine单个参数,传递时必须转换成指向void的指针类型。
没有参数传递时,可设置为NULL
*一个进程可以创建的线程最大数量取决于系统实现。
-一旦创建,线程就称为peers可以创建其它线程。
线程之间没有指定的结构和依赖关系。
thread3
time
f
Q:
—个线程被创建后,怎么知道操作系统何时调度该线程使之运行?
A:
除非使用了Pthreads的调度机制,否则线程何时何地被执行取决于操作系统的实现。
强壮的程序应该不依赖于线程执行的顺序。
I线程属性:
-线程被创建时会带有默认的属性。
其中的一些属性可以被程序员用线程属性对象来修改。
•pthread_attr_init和pthread_attr_destroy用于初始化/销毁先成属
性对象。
•其它的一些函数用于查询和设置线程属性对象的指定属性。
*一些属性下面将会讨论。
•结束线程的方法有一下几种:
o线程从主线程(main函数的初始线程)返回。
o线程调用了pthread_exit函数。
o其它线程使用pthread_cancel函数结束线程。
o调用exec或者exit函数,整个进程结束。
*pthread_exit用于显式退出线程。
典型地,pthread_exit()函数在线程
完成工作时,不在需要时候被调用,退出线程。
一
*如果main()在其他线程创建前用pthread_exit()退出了,其他线程将会继续执行。
否则,他们会随着main的结束而终止。
*程序员可以可选择的指定终止状态,当任何线程连接(join)该线程时,该状态就返回给连接(join)该线程的线程。
•清理:
pthread_exit()函数并不会关闭文件,任何在线程中打开的文件将会一直处于打开状态,知道线程结束。
•讨论:
对于正常退出,可以免于调用pthread_exit()。
当然,除非你想
返回一个返回值。
然而,在main中,有一个问题,就是当main结束时,其它线程还没有被创建。
如果此时没有显式的调用pthread_exit(),当
main结束时,进程(和所有线程)都会终止。
可以在main中调用pthread_exit(),此时尽管在main中已经没有可执行的代码了,进程和所有线程将保持存活状态,。
例子:
Pthread创建和终止
*该例用pthread_create()仓U建了5个线程。
每一个线程都会打印一条
“HelloWorld”的消息,然后调用pthread_exit()终止线程。
}pthread_exit(NULL);
}
SourcepOotput
线程管理
向线程传递参数
•pthread_create()函数允许程序员想线程的startroutine传递一个参
数。
当多个参数需要被传递时,可以通过定义一个结构体包含所有要传的参数,然后用pthread_create()传递一个指向改结构体的指针,来打破传递参数的个数的限制。
・所有参数都应该传引用传递并转化成(void*)。
T
怎样安全地向一个新创建的线程传递数据?
A:
确保所传递的数据是线程安全的(不能被其他线程修改)。
下面三个例子演示了那个应该和那个不应该。
Example1-ThreadArgumentPassing
下面的代码片段演示了如何向一个线程传递一个简单的整数。
主线程为每一个线程使用一个唯一的数据结构,确保每个线程传递的参数是完整的。
int*taskids[NUM_THREADS];
for(t=0;
t<
NUM_THREADS;
t++)
{
taskids[t]=(int*)malloc(sizeof(int));
*taskids[t]=t;
printf("
Creatingthread%d\n"
t);
rc=pthread_create(&
threads[t],NULL,PrintHello,(void*)taskids[t]);
SourcepOutput
的结构体实例
structthread_data{
intthread」d;
intsum;
char*message;
};
structthread_datathread_data_array[NUM_THREADS];
void*PrintHello(void*threadarg)
structthread_data*my_data;
my_data=(structthread_data*)threadarg;
taskid=my_data->
thread_id;
sum=my_data->
sum;
hello_msg=my_data->
message;
intmain(intargc,char*argv[])
thread_data_array[t].thread_id=t;
thread_data_array[t].sum=sum;
thread_data_array[t].message=messages[t];
threads[t],NULL,PrintHello,(void*)&
thread_data_array[t]);
3I
Example3-ThreadArgumentPassing(Incorrect)
例子演示了错误地传递参数。
循环会在线程访问传递的参数前改变传递给线程的地址的内容。
(void)&
t);
SourceOotput
连接(Joining)和分离(Detaching)线程
pthread_join(threadid,status)
pthreaddetach(threadid,status)
pthread_attr_setdetachstate(attr,detachstate)
pthread_attr_getdetachstate(attr,detachstate)
Worker
Thread
•pthread」oin()函数阻赛调用线程知道threadid所指定的线程终止。
*如果在目标线程中调用pthread_exit(),程序员可以在主线程中获得目标线程的终止状态。
•连接线程只能用pthread_join()连接一次。
若多次调用就会发生逻辑错误。
两种同步方法,互斥量(mutexes)和条件变量(conditionvariables),稍后讨论。
\可连接(Joinab
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- POSIX 线程 程序设计 中文版