Posix线程编程指南(经典)
在 POSIX 线程编程中避免内存泄漏
在POSIX 线程编程中避免内存泄漏检测和避免POSIX 线程内存泄漏的技巧Wei Dong Xie, IBM Systems Director 产品工程师, IBM简介: POSIX 线程(pthread)编程定义了一套标准的C 编程语言类型、函数和常量—且pthreads 提供了一种强大的线程管理工具。
要充分使用pthreads,您要避免常见错误。
一个常见的错误就是忘记联接可接合的线程,从而导致内存泄漏并增加工作量。
在该篇技巧型文章中,学习POSIX 线程基础,了解如何识别和检测线程内存泄漏,并获得避免出现这种情况的可靠建议。
POSIX 线程简介使用线程的主要原因是要提高程序性能。
线程的创建和管理只需要较小的操作系统开销和较少的系统资源。
一个进程内的所有线程共享相同的地址空间,使得线程间的通信更高效,且比进程间通信更易于实现。
例如,如果一个线程在等待一个输入/输出系统调用完成,其他线程可以处理CPU 密集型任务。
通过线程,可以优先调度重要任务—甚至中断—低优先级任务。
可将偶尔发生的任务放在定期调度的任务之间,创建调度灵活性。
最后,pthreads 是在多CPU 计算机上进行并行编程的理想之选。
而且使用POSIX 线程或pthreads 的主要原因更加简单:作为标准C 语言线程编程接口的一部分,它们可高可移植的。
POSIX 线程编程有诸多优势,但是如果您不明确一些基本规则,就有可能编写一些难以调试的代码并造成内存泄漏。
我们首先回顾一下POSIX 线程,分为可接合线程或分离线程。
可接合线程如果您希望生成一个新的线程,且需要知道它是如何终止的,那么您需要一个可接合线程。
对于可接合线程,系统分配专用存储器来存储线程终止状态。
线程终止后状态得到更新。
要获得线程终止状态,调用pthread_join(pthread_t thread, void** value_ptr)。
系统为每个线程分配底层存储,包括堆栈、线程ID、线程终止状态等。
Linux系统编程中的POSIX标准
Linux系统编程中的POSIX标准Linux系统编程在很长一段时间内一直在不断发展,随着POSIX标准的出现,Linux系统在该方面得到了全面的支持。
POSIX标准使得不同的Unix系统和其他操作系统之间的可移植性得到了很大的提高,这是Linux系统编程所必需的。
什么是POSIX?POSIX(Portable Operating System Interface,可移植操作系统接口)是由IEEE(Institute of Electrical and Electronics Engineers,电气和电子工程师学会)开发的一系列接口标准。
1990年,IEEE 正式颁发了POSIX标准的第一个版本,这个标准定义了许多操作系统接口的规范性要求,使得Unix的不同版本之间的软件可以轻松地进行移植。
POSIX标准的主旨是定义一组标准操作系统接口,使得应用程序的可移植性更好。
POSIX标准定义了一组与操作系统交互的API,包括文件操作、进程管理、信号传递等等。
POSIX标准在Linux中的应用在Linux系统中,POSIX标准已经得到了广泛的应用。
许多Linux上的C库都以POSIX标准为基础进行开发,例如glibc、bionic等等。
这些C库包含了POSIX标准中定义的一系列API,并提供了一些额外的功能。
开发者在编写应用程序时,可以使用这些API,从而使得应用程序更加规范,并且在其他系统上的移植性更好。
POSIX标准还提供了一个实现的方式,也就是POSIX兼容层。
POSIX兼容层是一个在Linux内核中的模块,它提供了一些非标准的API,这些API能够向后兼容POSIX标准。
这个兼容层让系统具有了更好的兼容性,比如在系统上运行一些遵循POSIX标准的旧应用程序时,可以使用这些非标准API进行支持。
在Linux系统中,可以使用一些工具来检查应用程序是否严格遵循了POSIX标准。
例如lint和splint工具,它们可以自动分析源代码,并提供一些有用的警告信息和其他功能。
Posix 多线程编程学习笔记(六)—共享内存(1)
off是要映射字节在文件中的起始偏移量。
通常将其设置为0。
prot参数说明对映射存储区的保护要求。
可将prot参数指定为PROT_NONE,或者是PROT_READ(映射区可读),PROT_WRITE(映射区可写),PROT_EXEC(映射区可执行)任意组合的按位或,也可以是PROT_NONE(映射区不可访问)。
对指定映射存储区的保护要求不能超过文件open模式访问权限。
flag参数影响映射区的多种属性:MAP_FIXED返回值必须等于addr.因为这不利于可移植性,所以不鼓励使用此标志。
MAP_SHARED这一标志说明了本进程对映射区所进行的存储操作的配置。
此标志指定存储操作修改映射文件。
MAP_PRIVATE本标志导致对映射区建立一个该映射文件的一个私有副本。
所有后来对该映射区的引用都是引用该副本,而不是原始文件。
要注意的是必须指定MAP_FIXED或MAP_PRIVATE标志其中的一个,指定前者是对存储映射文件本身的一个操作,而后者是对其副本进行操作。
mmap成功返回后,fd参数可以关闭。
该操作对于由mmap建立的映射关系没有影响。
为从某个进程的地址空间删除一个映射关系,我们调用munmap.2.名称::munmap功能:解除存储映射头文件:#include<sys/mman.h>函数原形:int munmap(caddr_t addr,size_t len);参数:addr指向映射存储区的起始地址len映射的字节返回值:若成功则返回0,若出错则返回-1其中addr参数是由mmap返回的地址,len是映射区的大小。
再次访问这些地址导致向调用进程产生一个SIGSEGV信号。
如果被映射区是使用MAP_PRIVATE标志映射的,那么调用进程对它所作的变动都被丢弃掉。
内核的虚存算法保持内存映射文件(一般在硬盘上)与内存映射区(在内存中)的同步(前提它是MAP_SHARED内存区)。
这就是说,如果我们修改了内存映射到某个文件的内存区中某个位置的内容,那么内核将在稍后某个时刻相应地更新文件。
POSIX thread
POSIX 线程详解 1POSIX(可移植操作系统接口)线程是提高代码响应和性能的有力手段。
在本系列中,Daniel Robbins 向您精确地展示在编程中如何使用线程。
其中还涉及大量幕后细节,读完本系列文章,您完全可以运用POSIX 线程创建多线程程序。
线程是有趣的了解如何正确运用线程是每一个优秀程序员必备的素质。
线程类似于进程。
如同进程,线程由内核按时间分片进行管理。
在单处理器系统中,内核使用时间分片来模拟线程的并发执行,这种方式和进程的相同。
而在多处理器系统中,如同多个进程,线程实际上一样可以并发执行。
那么为什么对于大多数合作性任务,多线程比多个独立的进程更优越呢?这是因为,线程共享相同的内存空间。
不同的线程可以存取内存中的同一个变量。
所以,程序中的所有线程都可以读或写声明过的全局变量。
如果曾用 fork() 编写过重要代码,就会认识到这个工具的重要性。
为什么呢?虽然 fork() 允许创建多个进程,但它还会带来以下通信问题: 如何让多个进程相互通信,这里每个进程都有各自独立的内存空间。
对这个问题没有一个简单的答案。
虽然有许多不同种类的本地 IPC (进程间通信),但它们都遇到两个重要障碍:强加了某种形式的额外内核开销,从而降低性能。
对于大多数情形,IPC 不是对于代码的“自然”扩展。
通常极大地增加了程序的复杂性。
双重坏事: 开销和复杂性都非好事。
如果曾经为了支持 IPC 而对程序大动干戈过,那么您就会真正欣赏线程提供的简单共享内存机制。
由于所有的线程都驻留在同一内存空间,POSIX 线程无需进行开销大而复杂的长距离调用。
只要利用简单的同步机制,程序中所有的线程都可以读取和修改已有的数据结构。
而无需将数据经由文件描述符转储或挤入紧窄的共享内存空间。
仅此一个原因,就足以让您考虑应该采用单进程/多线程模式而非多进程/单线程模式。
线程是快捷的不仅如此。
线程同样还是非常快捷的。
与标准 fork() 相比,线程带来的开销很小。
POXIS线程编程指南
POXIS线程编程指南杨沙洲(************)2001 年 10 月第一篇线程创建与取消这是一个关于Posix线程编程的专栏。
作者在阐明概念的基础上,将向您详细讲述Posix线程库API。
本文是第一篇将向您讲述线程的创建与取消。
一、线程创建1.1 线程与进程相对进程而言,线程是一个更加接近于执行体的概念,它可以与同进程中的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。
在串行程序基础上引入线程和进程是为了提高程序的并发度,从而提高程序运行效率和响应时间。
线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。
同时,线程适合于在SMP机器上运行,而进程则可以跨机器迁移。
1.2 创建线程POSIX通过pthread_create()函数创建线程,API定义如下:int pthread_create(pthread_t * thread, pthread_attr_t * attr,void * (*start_routine)(void *), void * arg)与fork()调用创建一个进程的方法不同,pthread_create()创建的线程并不具备与主线程(即调用pthread_create()的线程)同样的执行序列,而是使其运行start_routine(arg)函数。
thread 返回创建的线程ID,而attr是创建线程时设置的线程属性(见下)。
pthread_create()的返回值表示线程创建是否成功。
尽管arg是void *类型的变量,但它同样可以作为任意类型的参数传给start_routine()函数;同时,start_routine()可以返回一个void *类型的返回值,而这个返回值也可以是其他类型,并由pthread_join()获取。
1.3 线程创建属性pthread_create()中的attr参数是一个结构指针,结构中的元素分别对应着新线程的运行属性,主要包括以下几项:__detachstate,表示新线程是否与进程中其他线程脱离同步,如果置位则新线程不能用pthread_join()来同步,且在退出时自行释放所占用的资源。
5.6 POSIX线程编程
函数执行成功返回0,失败返回错误码。执行成功后, 新线程将从设定的函数处开始执行,原线程则继续执行。
退出线程
#include <pthread.h> void pthread_exit(void* ret)
终止调用此函数的线程,并返回一个指向某对象的指针 (ret)。注意,不能返回指向局部变量的指针。
void *thread_function(void *arg) #include <stdio.h> { #include <unistd.h> printf("thread_function is running. #include <stdlib.h> Argument was %s\n", (char *)arg); #include <pthread.h> sleep(3); strcpy(message, "Bye!"); void *thread_function(void *arg); you for the CPU time"); pthread_exit("Thank }
该宏必须定义在程序所有头文件包含之前
实现线程的函数
创建新线程:pthread_creat 终止线程:pthread_exit 合并线程:pthread_join
创建新线程
#include <pthread.h> int pthread_create( pthread_t* thread, //返回指向线程标识符的指针 pthread_attr* attr, //设置线程属性 void *(*func)(void*), //新线程将启动的函数的地址 void* arg //传递给新线程启动函数的参数);
07 POSIX线程
一个简单的线程化程序(3-1)
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> void *thread_function(void *arg); char message[] = “Hello World”; int main() { int res; pthread_t a_thread; void *thread_result; res = pthread_create(&a_thread,NULL,thread_function,(void*)message);
信号量示例程序(3-3)
sem_wait函数
作用:从信号量的值减去一个“1”,但它永远会先等待 该信号量为一个非零值才开始做减法
int sem_wait(sem_t *sem);
sem: 初始化的信号量对象的指针作为参数,用来改变该对象的 值 调用成功时 返回 0; 也是一个“原子操作”;
sem_destroy函数
作用:在ad_t th, void **thread_return);
th: 指定了将要等待的线程标识符 thread_return: 它指向另外一个指针,而后者指向线程的返回 值 成功时返回“0”,失败时返回一个错误代码 pthread_join相当于进程用来等待子进程的wait函数
线程函数库
与线程有关的函数构成了一个完整的系列,绝大多 数函数的名字都是以“pthread_”打头的
要使用这些函数库,要通过引入头文件<pthread.h>
链接这些线程函数库时要使用编译器命令的“ lpthread”选项
多线程编程之:Linux线程编程
多线程编程之:Linux线程编程9.2 线程编程9.2.1 线程基本编程这里要讲的线程相关操作都是用户空间中的线程的操作。
在Linux中,普通pthread线程库是一套通用的线程库,是由POSIX提出的,因此具有很好的可移植性。
(1)函数解释。
创建线程事实上就是确定调用该线程函数的入口点,这里通常用法的函数是pthread_create()。
在线程创建以后,就开头运行相关的线程函数,在该函数运行完之后,该线程也就退出了,这也是线程退出一种办法。
另一种退出线程的办法是用法函数pthread_exit(),这是线程的主动行为。
这里要注重的是,在用法线程函数时,不能任意用法exit()退出函数举行出错处理,因为exit()的作用是使调用进程终止,往往一个进程包含多个线程,因此,在用法exit()之后,该进程中的全部线程都终止了。
因此,在线程中就可以用法pthread_exit()来代替进程中的exit()。
因为一个进程中的多个线程是分享数据段的,因此通常在线程退出之后,退出线程所占用的资源并不会随着线程的终止而得到释放。
正如进程之间可以用wait()系统调用来同步终止并释放资源一样,线程之间也有类似机制,那就是pthread_join()函数。
pthread_join()可以用于将当前线程挂起来等待线程的结束。
这个函数是一个线程堵塞的函数,调用它的函数将向来等待到被等待的线程结束为止,当函数返回时,被等待线程的资源就被收回。
前面已提到线程调用pthread_exit()函数主动终止自身线程。
但是在无数线程应用中,常常会碰到在别的线程中要终止另一个线程的执行的问题。
此时调用pthread_cancel()函数实现这种功能,但在被取消的线程的内部需要调用pthread_setcancel()函数和pthread_setcanceltype()函数设置自己的取消状态,例如被取消的线第1页共9页。
pthread编程基础
pthread编程基础Linux系统下的多线程遵循POSIX线程接口,称为pthread。
编写Linux下的多线程程序,需要使用头文件pthread.h,连接时需要使用库libpthread.a。
与vxworks上任务的概念类似,都是调度的最小单元,都有共享的堆、栈、代码区、全局变量等。
2. 创建线程int pthread_create(pthread_t * thread,pthread_attr_t * attr,void * (*start_routine)(void *),void * arg)thread:返回创建的线程的IDattr:线程属性,调度策略、优先级等都在这里设置,如果为NULL则表示用默认属性start_routine:线程入口函数,可以返回一个void*类型的返回值,该返回值可由pthread_join()捕获arg:传给start_routine的参数,可以为NULL返回值:成功返回03. 设置线程属性线程属性通过attr进行设置。
设置与查询attr结构的为pthread_attr_get***()与pthread_attr_set***()两个函数系列。
设置与查询线程参数的为pthread_get***()与pthread_set***()两个函数系列。
也可以在创建时通过pthrea_create传入参数。
注:有些必须在线程创建时设置,如调度策略。
3.1. 调度策略调度策略有三种:SCHED_OTHER:非实时、正常SCHED_RR:实时、轮询法SCHED_FIFO:实时、先入先出,与vxworks的调度机制一致例程:pthread_attr_t attr;pthread_attr_init(&attr);pthread_attr_setschedpolicy(&attr,SCHED_FIFO);//sched_policy3.2. 优先级线程优先级支持两种设置方式,一种是创建时设置,另一种是创建后动态设置例程:pthread_attr_setschedparam(&attr, new_priority);如果是静态设置,则之后会用该属性创建任务,如果是动态设置,则使用下列函数设置:pthread_attr_setschedparam(&attr, &task->prv_priority);pthread_attr_getschedparam(&attr, &schedparam);schedparam.sched_priority = new_priority;pthread_attr_setschedparam(&attr, &schedparam);pthread_setschedparam(pthrid, sched_policy, &schedparam);3.3. 脱离同步Pthread_join()函数可以使主线程与子线程保持同步。
Posix多线程编程
一.什么是线程在一个程序里的多个执行路线就叫做线程。
更准确的定义是:线程是“一个进程内部的一个控制序列”。
典型的unix进程可以看成只有一个控制线程:一个进程在同一时刻只做一件事情。
有了多个控制线程以后,在程序设计时可以把进程设计成在同一时刻能够做不止一件事,每个线程处理各只独立的任务。
二.线程的优点(1)通过为每种事件类型的处理分配单独的线程,能够简化处理异步时间的代码。
(2)多个线程可以自动共享相同的存储地址空间和文件描述符。
(3)有些问题可以通过将其分解从而改善整个程序的吞吐量。
(4)交互的程序可以通过使用多线程实现相应时间的改善,多线程可以把程序中处理用户输入输出的部分与其它部分分开。
三.线程的缺点线程也有不足之处。
编写多线程程序需要更全面更深入的思考。
在一个多线程程序里,因时间分配上的细微偏差或者因共享了不该共享的变量而造成不良影响的可能性是很大的。
调试一个多线程程序也比调试一个单线程程序困难得多。
四.线程的结构线程包含了表示进程内执行环境必需的信息,其中包括进程中标识线程的线程ID,一组寄存器值、栈、调度优先级和策略、信号屏蔽子,errno变量以及线程私有数据。
进程的所有信息对该进程的所有线程都是共享的,包括可执行的程序文本,程序的全局内存和堆内存、栈以及文件描述符。
五.线程标识就像每个进程有一个进程ID一样,每个线程也有一个线程ID,进程ID在整个系统中是唯一的,但线程不同,线程ID只在它所属的进程环境中有效。
线程ID用pthread_t数据类型来表示,实现的时候可以用一个结构来代表pthread_t数据类型,所以可以移植的操作系统不能把它作为整数处理。
因此必须使用函数来对来对两个线程ID进行比较。
1.名称:pthread_equal功能:比较两个线程ID头文件:#include <pthread.h>函数原形:int pthread_equal(pthread_t tid1,pthread_t tid2);参数:tid1 进程1id, tid2 进程2id返回值:若相等返回非0值,否则返回02.名称:pthread_self功能:获取自身线程的id头文件:#include <pthread.h>函数原形:pthread_t pthread_self(void);参数:无返回值:调用线程的线程id六.线程的创建3.名称:pthread_create功能:创建线程头文件:#include <pthread.h>函数原形:int pthread_create(pthread_t *restrict tidp,const pthread _attr_t *restrict attr,void *(*start_rtn)(void),void *restrict arg);参数:返回值:若成功返回则返回0,否则返回错误编号当pthread_creat成功返回时,tidp指向的内存单元被设置为新创建线程的线程ID。
linux网络编程之POSIX消息队列和系列函数
A C/C++ Newbie每天进步一点点l inux网络编程之POSIX 消息队列 和 系列函数分类: linux网络编程 2013-06-16 10:54 569人阅读 评论(0) 收藏举报posix 消息队列一、在前面介绍了system v 消息队列的相关知识,现在来稍微看看posix 消息队列。
其实消息队列就是一个可以让进程间交换数据的场所,而两个标准的消息队列最大的不同可能只是api 函数的不同,如system v 的系列函数是msgxxx,而posix 是mq_xxx。
posix 消息队列也有一些对消息长度等的限制,man 7 mq_overview:simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ cat /proc/sys/fs/mqueue/msg_max10simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ cat /proc/sys/fs/mqueue/msgsize_max8192simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ cat /proc/sys/fs/mqueue/queues_max256即一个消息队列最多能有10条消息,每条消息的最大长度为8192字节,一个系统最多能有256个消息队列。
还有一点是,在Linux上,posix 消息队列是以虚拟文件系统实现的,必须将其挂载到某个目录才能看见,如# mkdir /dev/mqueue# mount -t mqueue none /dev/mqueue通过cat 命令查看消息队列的状态,假设mymq 是创建的一条消息队列的名字$ cat /dev/mqueue/mymqQSIZE:129 NOTIFY:2 SIGNO:0 NOTIFY_PID:8260QSIZE:消息队列所有消息的数据长度NOTIFY_PID:某个进程使用mq_notify 注册了消息到达异步通知事件,即此进程的pidNOTIFY:通知方式: 0 is SIGEV_SIGNAL; 1 is SIGEV_NONE; and 2 is SIGEV_THREAD.SIGNO:当以信号方式通知的时候,表示信号的编号.二、系列函数,编译时候加上 -lrt 选项,即连接librt 库 (实时库)#include <fcntl.h> /* For O_* constants */#include <sys/stat.h> /* For mode constants */#include <mqueue.h>功能:用来创建和访问一个消息队列原型mqd_t mq_open(const char *name, int oflag);mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr *attr);参数name: 某个消息队列的名字,必须以/打头,并且后续不能有其它/ ,形如/somename长度不能超过NAME_MAX(255)oflag:与open函数类似,可以是O_RDONLY、O_WRONLY、O_RDWR,还可以按位或上O_CREAT、O_EXCL、O_NONBLOCK;mode:如果oflag指定了O_CREAT,需要设置mode。
PThread
POSIX Threads ProgrammingTable of Contents111What are Pthreads?1Why Pthreads?1Designing Threaded Programs2The Pthreads API3Compiling Threaded ProgramsThread Management3Creating and Terminating Threads3Passing Arguments to Threads3Joining and Detaching Threads3Stack Management3Miscellaneous RoutinesMutex Variables3Mutex Variables Overview3Creating and Destroying Mutexes3Locking and Unlocking MutexesCondition Variables3Condition Variables Overview3Creating and Destroying Condition Variables3Waiting and Signaling on Condition Variables4LLNL Specific Information and Recommendations5Topics Not Covered6Pthread Library Routines Reference7References and More Information8In shared memory multiprocessor architectures,such as SMPs,threads can be used to implement parallelism. Historically,hardware vendors have implemented their own proprietary versions of threads,making portability a concern for software developers.For UNIX systems,a standardized C language threads programming interface has been specified by the IEEE POSIX1003.1c standard.Implementations that adhere to this standard are referred to as POSIX threads,or Pthreads.The tutorial begins with an introduction to concepts,motivations,and design considerations for using Pthreads.Each of the three major classes of routines in the Pthreads API are then covered:Thread Management,Mutex Variables,and Condition Variables.Example codes are used throughout to demonstrate how to use most of the Pthreads routines needed by a new Pthreads programmer.The tutorial concludes with a discussion of LLNL specifics and how to mix MPI with pthreads.A lab exercise,with numerous example codes(C Language)is also included.Level/Prerequisites:Ideal for those who are new to parallel programming with threads.A basic understanding of parallel programming in C is assumed.For those who are unfamiliar with Parallel Programming in general,the material covered in EC3500:Introduction To Parallel Computing would be helpful.Pthreads OverviewWhat is a Thread?•Technically,a thread is defined as an independent stream of instructions that can be scheduled to run as such by the operating system.But what does this mean?•To the software developer,the concept of a"procedure"that runs independently from its main program may best describe a thread.•To go one step further,imagine a main program(a.out)that contains a number of procedures.Then imagine all of these procedures being able to be scheduled to run simultaneously and/or independently by the operating system.That would describe a"multi-threaded"program.•How is this accomplished?•Before understanding a thread,one first needs to understand a UNIX process.A process is created by the operating system,and requires a fair amount of"overhead".Processes contain information about program resources and program execution state,including:o Process ID,process group ID,user ID,and group IDo Environmento Working directory.o Program instructionso Registerso Stacko Heapo File descriptorso Signal actionso Shared librarieso Inter-process communication tools(such as message queues,pipes,semaphores,or sharedmemory).••Threads use and exist within these process resources,yet are able to be scheduled by the operating system and run as independent entities largely because they duplicate only the bare essential resources that enable them to exist as executable code.•This independent flow of control is accomplished because a thread maintains its own:o Stack pointero Registerso Scheduling properties(such as policy or priority)o Set of pending and blocked signalso Thread specific data.•So,in summary,in the UNIX environment a thread:o Exists within a process and uses the process resourceso Has its own independent flow of control as long as its parent process exists and the OSsupports ito Duplicates only the essential resources it needs to be independently schedulableo May share the process resources with other threads that act equally independently(anddependently)o Dies if the parent process dies-or something similaro Is"lightweight"because most of the overhead has already been accomplished through thecreation of its process.•Because threads within the same process share resources:o Changes made by one thread to shared system resources(such as closing a file)will be seenby all other threads.o Two pointers having the same value point to the same data.o Reading and writing to the same memory locations is possible,and therefore requires explicitsynchronization by the programmer.Pthreads OverviewWhat are Pthreads?•Historically,hardware vendors have implemented their own proprietary versions of threads.These implementations differed substantially from each other making it difficult for programmers to develop portable threaded applications.•In order to take full advantage of the capabilities provided by threads,a standardized programming interface was required.o For UNIX systems,this interface has been specified by the IEEE POSIX1003.1c standard(1995).o Implementations adhering to this standard are referred to as POSIX threads,or Pthreads.o Most hardware vendors now offer Pthreads in addition to their proprietary API's.•The POSIX standard has continued to evolve and undergo revisions,including the Pthreads specification.The latest version is known as IEEE Std1003.1,2004Edition.•Some useful links:o POSIX FAQs:/austin/papers/posix_faq.htmlo Download the Standard:/version3/ieee_std.html•Pthreads are defined as a set of C language programming types and procedure calls,implemented with a pthread.h header/include file and a thread library-though this library may be part of another library,such as libc,in some implementations.Pthreads OverviewWhy Pthreads?••The primary motivation for using Pthreads is to realize potential program performance gains.•When compared to the cost of creating and managing a process,a thread can be created with much less operating system overhead.Managing threads requires fewer system resources than managing processes.For example,the following table compares timing results for the fork()subroutine and the pthread_create() subroutine.Timings reflect50,000process/thread creations,were performed with the time utility,and units are in seconds,no optimization flags.Note:don't expect the sytem and user times to add up to real time,because these are SMP systems with multiple CPUs working on the problem at the same time.At best,these are approximations run on local machines,past and present.•fork_vs_thread.txt•All threads within a process share the same address space.Inter-thread communication is more efficient and in many cases,easier to use than inter-process communication.•Threaded applications offer potential performance gains and practical advantages over non-threaded applications in several other ways:o Overlapping CPU work with I/O:For example,a program may have sections where it isperforming a long I/O operation.While one thread is waiting for an I/O system call to complete,CPU intensive work can be performed by other threads.o Priority/real-time scheduling:tasks which are more important can be scheduled to supersedeor interrupt lower priority tasks.o Asynchronous event handling:tasks which service events of indeterminate frequency andduration can be interleaved.For example,a web server can both transfer data from previousrequests and manage the arrival of new requests.•The primary motivation for considering the use of Pthreads on an SMP architecture is to achieve optimum performance.In particular,if an application is using MPI for on-node communications,there isa potential that performance could be greatly improved by using Pthreads for on-node data transferinstead.•For example:o MPI libraries usually implement on-node task communication via shared memory,whichinvolves at least one memory copy operation(process to process).oFor Pthreads there is no intermediate memory copy required because threads share the same address space within a single process.There is no data transfer,per se.It becomes more of a cache-to-CPU or memory-to-CPU bandwidth (worst case)situation.These speeds are much higher.o Some local comparisons are shown below:Platform MPI Shared Memory Bandwidth (GB/sec)Pthreads Worst Case Memory-to-CPU Bandwidth (GB/sec)AMD 2.3GHz Opteron 1.8 5.3AMD 2.4GHz Opteron 1.2 5.3IBM 1.9GHz POWER5p5-575 4.116IBM 1.5GHz POWER4 2.14Intel 2.4GHz Xeon 0.3 4.3Intel 1.4GHz Itanium 2 1.8 6.4Pthreads OverviewDesigning Threaded ProgramsParallel Programming:•On modern,multi-cpu machines,pthreads are ideally suited for parallel programming,and whatever applies to parallel programming in general,applies to parallel pthreads programs.•There are many considerations for designing parallel programs,such as:o What type of parallel programming model to use?o Problem partitioningo Load balancingo Communicationso Data dependencieso Synchronization and race conditionso Memory issueso I/O issueso Program complexityo Programmer effort/costs/time•Covering these topics is beyond the scope of this tutorial,however interested readers can obtain a quick overview in the Introduction to Parallel Computing tutorial.•In general though,in order for a program to take advantage of Pthreads,it must be able to be organized into discrete,independent tasks which can execute concurrently.For example,if routine1and routine2can be interchanged,interleaved and/or overlapped in real time,they are candidates for threading.•Programs having the following characteristics may be well suited for pthreads:o Work that can be executed,or data that can be operated on,by multiple tasks simultaneously o Block for potentially long I/O waitso Use many CPU cycles in some places but not otherso Must respond to asynchronous eventso Some work is more important than other work(priority interrupts)•Pthreads can also be used for serial applications,to emulate parallel execution.A perfect example is the typical web browser,which for most people,runs on a single cpu desktop/laptop machine.Many things can"appear"to be happening at the same time.•Several common models for threaded programs exist:oo Manager/worker:a single thread,the manager assigns work to other threads,the workers.Typically,the manager handles all input and parcels out work to the other tasks.At least two forms of the manager/worker model are common:static worker pool and dynamic worker pool.o Pipeline:a task is broken into a series of suboperations,each of which is handled in series,but concurrently,by a different thread.An automobile assembly line best describes this model.o Peer:similar to the manager/worker model,but after the main thread creates other threads,it participates in the work.Shared Memory Model:•All threads have access to the same global,shared memory•Threads also have their own private data•Programmers are responsible for synchronizing access(protecting)globally shared data.Thread-safeness:•Thread-safeness:in a nutshell,refers an application's ability to execute multiple threads simultaneously without"clobbering"shared data or creating"race"conditions.•For example,suppose that your application creates several threads,each of which makes a call to the same library routine:o This library routine accesses/modifies a global structure or location in memory.o As each thread calls this routine it is possible that they may try to modify this global structure/memory location at the same time.o If the routine does not employ some sort of synchronization constructs to prevent data corruption,then it is not thread-safe.•The implication to users of external library routines is that if you aren't100%certain the routine is thread-safe,then you take your chances with problems that could arise.•Recommendation:Be careful if your application uses libraries or other objects that don't explicitly guarantee thread-safeness.When in doubt,assume that they are not thread-safe until proven otherwise. This can be done by"serializing"the calls to the uncertain routine,etc.The Pthreads API••The original Pthreads API was defined in the ANSI/IEEE POSIX1003.1-1995standard.The POSIX standard has continued to evolve and undergo revisions,including the Pthreads specification.The latest version is known as IEEE Std1003.1,2004Edition.•Copies of the standard can be purchased from IEEE or downloaded for free from /version3/ieee_std.html.•The subroutines which comprise the Pthreads API can be informally grouped into four major groups: 88Thread management:Routines that work directly on threads-creating,detaching,joining, etc.They also include functions to set/query thread attributes(joinable,scheduling etc.)8Mutexes:Routines that deal with synchronization,called a"mutex",which is an abbreviation for"mutual exclusion".Mutex functions provide for creating,destroying,locking and unlocking mutexes.These are supplemented by mutex attribute functions that set or modify attributes associated with mutexes.8Condition variables:Routines that address communications between threads that share a mutex.Based upon programmer specified conditions.This group includes functions to create, destroy,wait and signal based upon specified variable values.Functions to set/query condition variable attributes are also included.8Synchronization:Routines that manage read/write locks and barriers.•Naming conventions:All identifiers in the threads library begin with pthread_.Some examples are shown below.Routine Prefix Functional Grouppthread_Threads themselves and miscellaneous subroutinespthread_attr_Thread attributes objectspthread_mutex_Mutexespthread_mutexattr_Mutex attributes objects.pthread_cond_Condition variablespthread_condattr_Condition attributes objectspthread_key_Thread-specific data keyspthread_rwlock_Read/write lockspthread_barrier_Synchronization barriers••The concept of opaque objects pervades the design of the API.The basic calls work to create or modify opaque objects-the opaque objects can be modified by calls to attribute functions,which deal with opaque attributes.•The Pthreads API contains around100subroutines.This tutorial will focus on a subset of these-specifically,those which are most likely to be immediately useful to the beginning Pthreads programmer.•For portability,the pthread.h header file should be included in each source file using the Pthreads library.•The current POSIX standard is defined only for the C language.Fortran programmers can use wrappers around C function calls.Some Fortran compilers(like IBM AIX Fortran)may provide a Fortram pthreads API.•A number of excellent books about Pthreads are available.Several of these are listed in the••Several examples of compile commands used for pthreads codes are listed in the table below.Compiler/PlatformCompiler Command DescriptionIBM AIX xlc_r/cc_r C(ANSI/non-ANSI)xlC_r C++xlf_r-qnosavexlf90_r-qnosaveFortran-using IBM's Pthreads API(non-portable)INTEL Linux icc-pthread C icpc-pthread C++PathScale Linux pathcc-pthread C pathCC-pthread C++PGI Linux pgcc-lpthread C pgCC-lpthread C++GNU Linux,AIX gcc-pthread GNU Cg++-pthread GNU C++•Thread Management Creating and Terminating ThreadsCreating Threads:••Initially,your main()program comprises a single,default thread.All other threads must be explicitly created by the programmer.•pthread_createcreates a new thread and makes it executable.This routine can be called any number of times from anywhere within your code.•pthread_createarguments:o thread:An opaque,unique identifier for the new thread returned by the subroutine.o attr:An opaque attribute object that may be used to set thread attributes.You can specify a thread attributes object,or NULL for the default values.o start_routine:the C routine that the thread will execute once it is created.o arg:A single argument that may be passed to start_routine.It must be passed by reference asa pointer cast of type void.NULL may be used if no argument is to be passed.•The maximum number of threads that may be created by a process is implementation dependent.•Once created,threads are peers,and may create other threads.There is no implied hierarchy or dependency between threads.Question:After a thread has been created,how do you know when it will bescheduled to run by the operating system?Thread Attributes:••By default,a thread is created with certain attributes.Some of these attributes can be changed by the programmer via the thread attribute object.•pthread_attr_initand pthread_attr_destroy are used to initialize/destroy the thread attribute object.•Other routines are then used to query/set specific attributes in the thread attribute object.•Some of these attributes will be discussed later.Terminating Threads:••There are several ways in which a Pthread may be terminated:o The thread returns from its starting routine(the main routine for the initial thread).o The thread makes a call to the pthread_exit subroutine(covered below).o The thread is canceled by another thread via the pthread_cancel routine(not covered here).o The entire process is terminated due to a call to either the exec or exit subroutines.•pthread_exitis used to explicitly exit a thread.Typically,the pthread_exit()routine is called after a thread has completed its work and is no longer required to exist.•If main()finishes before the threads it has created,and exits with pthread_exit(),the other threads will continue to execute.Otherwise,they will be automatically terminated when main()finishes.•The programmer may optionally specify a termination status,which is stored as a void pointer forany thread that may join the calling thread.•Cleanup:the pthread_exit()routine does not close files;any files opened inside the thread will remain open after the thread is terminated.•Discussion:In subroutines that execute to completion normally,you can often dispense with calling pthread_exit()-unless,of course,you want to pass a return code back.However,in main(),there is a definite problem if main()completes before the threads it spawned.If you don't call pthread_exit() explicitly,when main()completes,the process(and all threads)will be terminated.By calling pthread_exit()in main(),the process and all of its threads will be kept alive even though all of the code in main()has been executed.Example:Pthread Creation and Termination••This simple example code creates5threads with the pthread_create()routine.Each thread prints a "Hello World!"message,and then terminates with a call to pthread_exit().Example Code-Pthread Creation and Termination#include<pthread.h>#include<stdio.h>#define NUM_THREADS5void*PrintHello(void*threadid){long tid;tid=(long)threadid;printf("Hello World!It's me,thread#%ld!\n",tid);pthread_exit(NULL);}int main(int argc,char*argv[]){pthread_t threads[NUM_THREADS];int rc;long t;for(t=0;t<NUM_THREADS;t++){printf("In main:creating thread%ld\n",t);rc=pthread_create(&threads[t],NULL,PrintHello,(void*)t);if(rc){printf("ERROR;return code from pthread_create()is%d\n",rc);exit(-1);}}pthread_exit(NULL);}•Thread ManagementPassing Arguments to Threads••The pthread_create()routine permits the programmer to pass one argument to the thread start routine.For cases where multiple arguments must be passed,this limitation is easily overcome by creating a structure which contains all of the arguments,and then passing a pointer to that structure in the pthread_create()routine.•All arguments must be passed by reference and cast to(void*).Question:How can you safely pass data to newly created threads,given theirnon-deterministic start-up and scheduling?hello_msg=my_data->message;...}int main(int argc,char*argv[]){...thread_data_array[t].thread_id=t;thread_data_array[t].sum=sum;thread_data_array[t].message=messages[t];rc=pthread_create(&threads[t],NULL,PrintHello,(void*)&thread_data_array[t]);...}Thread ManagementJoining and Detaching ThreadsJoining:••"Joining"is one way to accomplish synchronization between threads.For example:•The pthread_join()subroutine blocks the calling thread until the specified threadid thread terminates.•The programmer is able to obtain the target thread's termination return status if it was specified in the target thread's call to pthread_exit().•A joining thread can match one pthread_join()call.It is a logical error to attempt multiple joins on the same thread.•Two other synchronization methods,mutexes and condition variables,will be discussed later.Joinable or Not?••When a thread is created,one of its attributes defines whether it is joinable or detached.Only threads that are created as joinable can be joined.If a thread is created as detached,it can never be joined.•The final draft of the POSIX standard specifies that threads should be created as joinable.•To explicitly create a thread as joinable or detached,the attr argument in the pthread_create()routine is used.The typical4step process is:8Declare a pthread attribute variable of the pthread_attr_t data type8Initialize the attribute variable with pthread_attr_init()8Set the attribute detached status with pthread_attr_setdetachstate()8When done,free library resources used by the attribute with pthread_attr_destroy()Detaching:••The pthread_detach()routine can be used to explicitly detach a thread even though it was created as joinable.•There is no converse routine.Recommendations:••If a thread requires joining,consider explicitly creating it as joinable.This provides portability as not all implementations may create threads as joinable by default.•If you know in advance that a thread will never need to join with another thread,consider creating it in a detached state.Some system resources may be able to be freed.Example:Pthread Joining/*Free attribute and wait for the other threads*/pthread_attr_destroy(&attr);for(t=0;t<NUM_THREADS;t++){rc=pthread_join(thread[t],&status);if(rc){printf("ERROR;return code from pthread_join()is%d\n",rc);exit(-1);}printf("Main:completed join with thread%ld having a statusof%ld\n",t,(long)status);}printf("Main:program completed.Exiting.\n");pthread_exit(NULL);}Thread ManagementStack ManagementPreventing Stack Problems:••The POSIX standard does not dictate the size of a thread's stack.This is implementation dependent and varies.•Exceeding the default stack limit is often very easy to do,with the usual results:program termination and/or corrupted data.•Safe and portable programs do not depend upon the default stack limit,but instead,explicitly allocate enough stack for each thread by using the pthread_attr_setstacksize routine.•The pthread_attr_getstackaddr and pthread_attr_setstackaddr routines can be used by applications in an environment where the stack for a thread must be placed in some particular region of memory.Some Practical Examples at LC:••Default thread stack size varies greatly.The maximum size that can be obtained also varies greatly,and may depend upon the number of threads per node.Node Architecture #CPUsMemory(GB)Default Size(bytes)AMD Opteron8162,097,152Intel IA644833,554,432Intel IA32242,097,152IBM Power5832196,608IBM Power4816196,608IBM Power3161698,304•Example:Stack Managementpthread_attr_init(&attr);pthread_attr_getstacksize(&attr,&stacksize);printf("Default stack size=%li\n",stacksize);stacksize=sizeof(double)*N*N+MEGEXTRA;printf("Amount of stack needed per thread=%li\n",stacksize);pthread_attr_setstacksize(&attr,stacksize);printf("Creating threads with stack size=%li bytes\n",stacksize);for(t=0;t<NTHREADS;t++){rc=pthread_create(&threads[t],&attr,dowork,(void*)t);if(rc){printf("ERROR;return code from pthread_create()is%d\n",rc);exit(-1);}}printf("Created%ld threads.\n",t);pthread_exit(NULL);}Thread ManagementMiscellaneous Routines•pthread_selfreturns the unique,system assigned thread ID of the calling thread.•pthread_equalcompares two thread IDs.If the two IDs are different0is returned,otherwise a non-zero value is returned.•Note that for both of these routines,the thread identifier objects are opaque and can not be easily inspected.Because thread IDs are opaque objects,the C language equivalence operator==should not be used to compare two thread IDs against each other,or to compare a single thread ID against another value.••pthread_onceexecutes the init_routine exactly once in a process.The first call to this routine by any thread in the process executes the given init_routine,without parameters.Any subsequent call will have no effect.•The init_routine routine is typically an initialization routine.•The once_control parameter is a synchronization control structure that requires initialization prior to calling pthread_once.For example:pthread_once_t once_control=PTHREAD_ONCE_INIT;Mutex VariablesOverview••Mutex is an abbreviation for"mutual exclusion".Mutex variables are one of the primary means of implementing thread synchronization and for protecting shared data when multiple writes occur.•A mutex variable acts like a"lock"protecting access to a shared data resource.The basic concept of a mutex as used in Pthreads is that only one thread can lock(or own)a mutex variable at any given time.Thus,even if several threads try to lock a mutex only one thread will be successful.No other thread can own that mutex until the owning thread unlocks that mutex.Threads must"take turns"accessing protected data.•Mutexes can be used to prevent"race"conditions.An example of a race condition involving a bank transaction is shown below:Thread1Thread2BalanceRead balance:$1000$1000Read balance:$1000$1000Deposit$200$1000Deposit$200$1000Update balance$1200$1000+$200Update balance$1200$1000+$200••In the above example,a mutex should be used to lock the"Balance"while a thread is using this shared data resource.•Very often the action performed by a thread owning a mutex is the updating of global variables.This is a safe way to ensure that when several threads update the same variable,the final value is the same as what it would be if only one thread performed the update.The variables being updated belong to a "critical section".•A typical sequence in the use of a mutex is as follows:o Create and initialize a mutex variableo Several threads attempt to lock the mutexo Only one succeeds and that thread owns the mutexo The owner thread performs some set of actionso The owner unlocks the mutexo Another thread acquires the mutex and repeats the processo Finally the mutex is destroyed•When several threads compete for a mutex,the losers block at that call-an unblocking call is available with"trylock"instead of the"lock"call.•When protecting shared data,it is the programmer's responsibility to make sure every thread that needs to use a mutex does so.For example,if4threads are updating the same data,but only one uses a mutex,the data can still be corrupted.Mutex VariablesCreating and Destroying MutexesRoutines:。
POSIX操作系统串行编程指南
POSIX操作系统串行编程指南5th Edition, 3rd RevisionCopyright 1994-2003 by Michael R. Sweet允许拷贝,分发或在GNU自由文档许可(Version 1.2 或任何更新的由自由软件基金会发布的版本)的条件下的修改,不可有任何章节的变化,额外的开头和结尾文字。
一份许可包含在附录C, GNU自由文档许可.目录介绍∙许可∙组织第一章,串行通讯基础∙什么是串行通讯?∙什么是RS-232?o信号定义∙异步通讯o什么是全双工和半双工?o流控制o什么是中断?∙同步通讯∙访问串口o串口文件o打开一个串口o写数据到端口o从端口读取数据o关闭串口第二章,设置串口∙POSIX终端接口o控制项o本地项o输入项o输出项o控制字符第三章,MODEM通讯∙什么是MODEM?∙与一MODEM设备通讯o标准MODEM指令o见MODEM通讯问题第四章,高级串口编程∙串口IOCTLso获得控信号o设置串口控制信号o获得可用的字节数目∙从一串口选择输入o SELECT系统呼叫o使用SELECT系统呼叫o使SELECT与X内置库联用附录A,引脚∙RS-232引脚∙RS-422引脚∙RS-574(IBM PC/AT)引脚∙SGI引脚附录B,ASCII控制码∙控制码附录C,GNU自由文档许可附录D,修改历史∙版本5 ,第3次修订介绍POSIX 操作系统串行编程指南将教会你如何成功、有效和可移植地在你的UNIX?工作站或PC上编程。
每章提供的编程样例使用POSIX (UNIX可移植标准)终端控制函数,少量修改就可以运行于IRIX®, HP-UX, SunOS®, Solaris®, Digital UNIX®, Linux®, 和许多其它的UNIX操作系统。
你将发现在不同操作系统之间的最大差别是串口设备和锁定文件的名字。
许可在GNU自由文档许可(版本1.2或更新的,由自由软件基金发布的版本)的条件下,允许复制、分发或修改这个文档;不能改变章节,不能有开头和结尾的附加文本。
Linuxthread最基本用法
Linuxthread最基本用法关于POSIX thread的最基本用法要用到线程,但对线程一直不怎么懂,看了些资料作了两个例子和总结,不对的地方恳请各位指正。
1.基本函数pthread_create,pthread_detach,pthread_join,pthread_exit,pthread_self具体的意义和参数看man或者书吧,其他的函数还不会用。
2.基本用法程序1程序功能:main产生一个线程,线程根据main传来的参数产生几个60-100的随机数;main待线程退出后退出。
1 #include <stdlib.h>2 #include <stdio.h>3 #include <pthread.h>4 #include <time.h>56 int myRand(void* cnt)7 {8 int min = 60;9 int max = 100;10 int randCnt = *((int *)cnt);11 int i = 0;12 pthread_t thread_id = pthread_self();1314 /* init the random seed */15 srand((unsigned int)time(NULL));16 for(; i < randCnt; i ++){17 /* create random number in [60, 100) */18 printf("thread_id = %d rand()%02d = %d"n",19 thread_id, i, min + rand() % (max - min));20 sleep(1);21 }22 //return 11;23 pthread_exit((void*)11);24 }2526 int main(int argc, char* argv[])27 {28 pthread_t tid;29 void* result;30 int reqRandCnt = 5;3132 if(pthread_create(&tid, NULL, (void *)myRand, (void *)&reqRandCnt) == 0){33 printf("myRand thread create OK!"n");34 //pthread_detach(tid);35 }36 if(pthread_join(tid, &result) == 0){37 printf("thread tid = %d, result = %d"n", tid, (int)result);38 }39 return 0;40 //pthread_exit((void*)22);41 }一次运行结果:thread_id = 1082367168 rand()00 = 95myRand thread create OK!thread_id = 1082367168 rand()01 = 71thread_id = 1082367168 rand()02 = 63thread_id = 1082367168 rand()03 = 81thread_id = 1082367168 rand()04 = 66thread tid = 1082367168, result = 11几点说明1)main用pthread_create产生一个线程,最主要的是后第三第四个参数,第三参数是完成线程的函数,第四参数是传给线程的参数。
POSIX线程程序设计(中文版)
POSIX 多线程程序设计Blaise Barney, Lawrence Livermore National Laboratory目录表1.摘要2.Pthreads 概述1.什么是线程?2.什么是Pthreads?3.为什么使用Pthreads?4.使用线程设计程序3.Pthreads API编译多线程程序4.线程管理1.创建和终止线程2.向线程传递参数3.连接(Joining)和分离(Detaching)线程4.栈管理5.其它函数5.互斥量(Mutex Variables)1.互斥量概述2.创建和销毁互斥量3.锁定(Locking)和解锁(Unlocking)互斥量6.条件变量(Condition Variable)1.条件变量概述2.创建和销毁条件变量3.等待(Waiting)和发送信号(Signaling)7.没有覆盖的主题8.Pthread 库API参考9.参考资料在多处理器共享内存的架构中(如:对称多处理系统SMP),线程可以用于实现程序的并行性。
历史上硬件销售商实现了各种私有版本的多线程库,使得软件开发者不得不关心它的移植性。
对于UNIX系统,IEEE POSIX 1003.1标准定义了一个C语言多线程编程接口。
依附于该标准的实现被称为POSIX theads 或Pthreads。
该教程介绍了Pthreads的概念、动机和设计思想。
内容包含了Pthreads API主要的三大类函数:线程管理(Thread Managment)、互斥量(Mutex Variables)和条件变量(Condition Variables)。
向刚开始学习Pthreads的程序员提供了演示例程。
适于:刚开始学习使用线程实现并行程序设计;对于C并行程序设计有基本了解。
不熟悉并行程序设计的可以参考EC3500: Introduction To Parallel Computing。
什么是线程?•技术上,线程可以定义为:可以被操作系统调度的独立的指令流。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Posix线程编程指南Posix线程编程指南 (1)一线程创建与取消 (3)线程创建 (3)1.线程与进程 (3)2. 创建线程 (3)3. 线程创建属性 (3)4. 创建的Linux实现 (4)线程取消 (4)1. 消的定义 (4)2. 线程取消的语义 (4)3. 取消点 (5)4. 程序设计方面的考虑 (5)5. 与线程取消相关的pthread函数 (5)二线程私有数据 (5)1. 概念及作用 (6)2. 创建和注销 (6)3. 访问 (6)4. 使用范例 (7)三线程同步 (8)互斥锁 (8)1.创建和销毁 (8)2.互斥锁属性 (9)3.锁操作 (9)4.其他 (9)条件变量 (10)1.创建和注销 (10)2.等待和激发 (10)3.其他 (11)信号灯 (12)1.创建和注销 (12)2.点灯和灭灯 (13)3.获取灯值 (13)4.其他 (13)异步信号 (13)其他同步方式 (14)四线程终止 (14)线程终止方式 (14)线程终止时的清理 (14)线程终止的同步及其返回值 (16)关于pthread_exit()和return (16)五杂项 (16)获得本线程ID (17)判断两个线程是否为同一线程 (17)仅执行一次的操作 (17)一线程创建与取消这是一个关于Posix线程编程的专栏。
作者在阐明概念的基础上,将向您详细讲述Posix线程库API。
本文是第一篇将向您讲述线程的创建与取消。
线程创建1.线程与进程相对进程而言,线程是一个更加接近于执行体的概念,它可以与同进程中的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。
在串行程序基础上引入线程和进程是为了提高程序的并发度,从而提高程序运行效率和响应时间。
线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。
同时,线程适合于在SMP机器上运行,而进程则可以跨机器迁移。
2. 创建线程POSIX通过pthread_create()函数创建线程,API定义如下:与fork()调用创建一个进程的方法不同,pthread_create()创建的线程并不具备与主线程(即调用pthread_create()的线程)同样的执行序列,而是使其运行start_routine(arg)函数。
thread返回创建的线程ID,而attr是创建线程时设置的线程属性(见下)。
pthread_create()的返回值表示线程创建是否成功。
尽管arg是void *类型的变量,但它同样可以作为任意类型的参数传给start_routine()函数;同时,start_routine()可以返回一个void *类型的返回值,而这个返回值也可以是其他类型,并由pthread_join()获取。
3. 线程创建属性pthread_create()中的attr参数是一个结构指针,结构中的元素分别对应着新线程的运行属性,主要包括以下几项:__detachstate,表示新线程是否与进程中其他线程脱离同步,如果置位则新线程不能用pthread_join()来同步,且在退出时自行释放所占用的资源。
缺省为PTHREAD_CREATE_JOINABLE状态。
这个属性也可以在线程创建并运行以后用pthread_detach()来设置,而一旦设置为PTHREAD_CREATE_DETACH 状态(不论是创建时设置还是运行时设置)则不能再恢复到PTHREAD_CREATE_JOINABLE状态。
__schedpolicy,表示新线程的调度策略,主要包括SCHED_OTHER(正常、非实时)、SCHED_RR (实时、轮转法)和SCHED_FIFO(实时、先入先出)三种,缺省为SCHED_OTHER,后两种调度策略仅对超级用户有效。
运行时可以用过pthread_setschedparam()来改变。
__schedparam,一个struct sched_param结构,目前仅有一个sched_priority整型变量表示线程的运行优先级。
这个参数仅当调度策略为实时(即SCHED_RR或SCHED_FIFO)时才有效,并可以在运行时通过pthread_setschedparam()函数来改变,缺省为0。
__inheritsched,有两种值可供选择:PTHREAD_EXPLICIT_SCHED和PTHREAD_INHERIT_SCHED,前者表示新线程使用显式指定调度策略和调度参数(即attr中的值),而后者表示继承调用者线程的值。
缺省为PTHREAD_EXPLICIT_SCHED。
__scope,表示线程间竞争CPU的范围,也就是说线程优先级的有效范围。
POSIX的标准中定义了两个值:PTHREAD_SCOPE_SYSTEM和PTHREAD_SCOPE_PROCESS,前者表示与系统中所有线程一起竞争CPU时间,后者表示仅与同进程中的线程竞争CPU。
目前LinuxThreads仅实现了PTHREAD_SCOPE_SYSTEM一值。
pthread_attr_t结构中还有一些值,但不使用pthread_create()来设置。
为了设置这些属性,POSIX定义了一系列属性设置函数,包括pthread_attr_init()、pthread_attr_destroy()和与各个属性相关的pthread_attr_get---/pthread_attr_set---函数。
4. 创建的Linux实现我们知道,Linux的线程实现是在核外进行的,核内提供的是创建进程的接口do_fork()。
内核提供了两个系统调用__clone()和fork(),最终都用不同的参数调用do_fork()核内API。
当然,要想实现线程,没有核心对多进程(其实是轻量级进程)共享数据段的支持是不行的,因此,do_fork()提供了很多参数,包括CLONE_VM(共享内存空间)、CLONE_FS(共享文件系统信息)、CLONE_FILES(共享文件描述符表)、CLONE_SIGHAND(共享信号句柄表)和CLONE_PID(共享进程ID,仅对核内进程,即0号进程有效)。
当使用fork系统调用时,内核调用do_fork()不使用任何共享属性,进程拥有独立的运行环境,而使用pthread_create()来创建线程时,则最终设置了所有这些属性来调用__clone(),而这些参数又全部传给核内的do_fork(),从而创建的"进程"拥有共享的运行环境,只有栈是独立的,由__clone()传入。
Linux线程在核内是以轻量级进程的形式存在的,拥有独立的进程表项,而所有的创建、同步、删除等操作都在核外pthread库中进行。
pthread库使用一个管理线程(__pthread_manager(),每个进程独立且唯一)来管理线程的创建和终止,为线程分配线程ID,发送线程相关的信号(比如Cancel),而主线程(pthread_create())的调用者则通过管道将请求信息传给管理线程。
线程取消1. 消的定义一般情况下,线程在其主体函数退出的时候会自动终止,但同时也可以因为接收到另一个线程发来的终止(取消)请求而强制终止。
2. 线程取消的语义线程取消的方法是向目标线程发Cancel信号,但如何处理Cancel信号则由目标线程自己决定,或者忽略、或者立即终止、或者继续运行至Cancelation-point(取消点),由不同的Cancelation状态决定。
线程接收到CANCEL信号的缺省处理(即pthread_create()创建线程的缺省状态)是继续运行至取消点,也就是说设置一个CANCELED状态,线程继续运行,只有运行至Cancelation-point的时候才会退出。
3. 取消点根据POSIX标准,pthread_join()、pthread_testcancel()、pthread_cond_wait()、pthread_cond_timedwait()、sem_wait()、sigwait()等函数以及read()、write()等会引起阻塞的系统调用都是Cancelation-point,而其他pthread函数都不会引起Cancelation动作。
但是pthread_cancel的手册页声称,由于LinuxThread库与C库结合得不好,因而目前C库函数都不是Cancelation-point;但CANCEL信号会使线程从阻塞的系统调用中退出,并置EINTR错误码,因此可以在需要作为Cancelation-point的系统调用前后调用pthread_testcancel(),从而达到POSIX标准所要求的目标,即如下代码段:4. 程序设计方面的考虑如果线程处于无限循环中,且循环体内没有执行至取消点的必然路径,则线程无法由外部其他线程的取消请求而终止。
因此在这样的循环体的必经路径上应该加入pthread_testcancel()调用。
5. 与线程取消相关的pthread函数int pthread_cancel(pthread_t thread)发送终止信号给thread线程,如果成功则返回0,否则为非0值。
发送成功并不意味着thread会终止。
int pthread_setcancelstate(int state, int *oldstate)设置本线程对Cancel信号的反应,state有两种值:PTHREAD_CANCEL_ENABLE(缺省)和PTHREAD_CANCEL_DISABLE,分别表示收到信号后设为CANCLED状态和忽略CANCEL信号继续运行;old_state如果不为NULL则存入原来的Cancel状态以便恢复。
int pthread_setcanceltype(int type, int *oldtype)设置本线程取消动作的执行时机,type由两种取值:PTHREAD_CANCEL_DEFFERED和PTHREAD_CANCEL_ASYCHRONOUS,仅当Cancel状态为Enable时有效,分别表示收到信号后继续运行至下一个取消点再退出和立即执行取消动作(退出);oldtype如果不为NULL则存入运来的取消动作类型值。
void pthread_testcancel(void)检查本线程是否处于Canceld状态,如果是,则进行取消动作,否则直接返回。
二线程私有数据这是一个关于Posix线程编程的专栏。
作者在阐明概念的基础上,将向您详细讲述Posix线程库API。
本文是第二篇将向您讲述线程的私有数据。
1. 概念及作用在单线程程序中,我们经常要用到"全局变量"以实现多个函数间共享数据。