第 11 章 多线程技术_第1页
第 11 章 多线程技术_第2页
第 11 章 多线程技术_第3页
第 11 章 多线程技术_第4页
第 11 章 多线程技术_第5页
已阅读5页,还剩53页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第11章多线程技术内容提要线程概述创建新进程线程控制线程取消线程同步多线程环境下的信号处理非线程安全函数的改造11.1线程概述线程概述

线程如同进程是系统可独立调度的最小执行单元,它们仅在资源的使用方式上有所不同,进程间的用户地址空间彼此独立,然而,线程却共享创建者进程的用户地址空间等资源。引入线程的目的是为了减少对资源的消耗。创建新进程时,用户可根据需求定制进程,,进程和线程为两种最常见的新进程定制类型。进程与线程的关系栈(stack)文件描述符表栈(stack)代码段(text)数据段(data)堆(heap)文件描述符表代码段(text)数据段(data)堆(heap)线程线程栈(stack)进程多线程进程Linux线程的实现

由于线程诞生的时间较晚,早期的操作系统内核并不支持线程。1.用户线程对不支持内核线程的操作系统,通过编程技巧,在一个进程中,可模拟出多条被称为用户线程的执行路径,但用户线程存在很多不足。2.内核线程内核线程通过修改内核代码实现,目前,现代操作系统均支持内核线程。Linux线程的实现(续)1.LinuxThreads

LinuxThreads为POSIX线程库的早期版本,自glibc2.4起不再使用,因受当时内核对线程支持不足的影响,LinuxThreads仅实现了POSIX线程的部分标准。2.NPTL

NPTL(NativePOSIXThreadsLibrary)属于POSIX线程库的现代版本,最早出现于glibc2.3.2,需内核2.6以上版本的支持。相较于LinuxThreads,NPTL更符合POSIX标准,在创建大量线程的情况下,具有更高的性能。应用编程接口分类API功能描述创建新进程clone创建新的进程线程属性pthread_attr_init初始化线程属性对象pthread_attr_destroy注销线程属性对象pthread_attr_getstack获取线程栈的地址和大小pthread_attr_setstack设置线程栈的地址和大小pthread_attr_getdetachstate获取线程的分离属性pthread_attr_setdetachstate设置线程的分离属性pthread_create创建线程pthread_join等待线程运行结束pthread_exit结束线程线程取消pthread_cancel向线程发送取消请求pthread_setcancelstate设置线程取消的状态pthread_setcanceltype设置线程取消的类型pthread_testcancel测试线程的取消请求是否到达pthread_cleanup_push注册线程清理函数应用编程接口线程同步互斥锁pthread_mutex_init初始化互斥锁pthread_mutex_destroy注销互斥锁pthread_mutex_lock申请获得互斥锁pthread_mutex_unlock释放互斥锁条件变量pthread_cond_init条件变量的初始化pthread_cond_wait等待条件变量pthread_cond_signal唤醒等待条件变量的线程pthread_cond_destroy注销条件变量线程的信号处理pthread_kill向线程发送信号pthread_sigqueue向线程发送实时信号pthread_sigmask设置线程的信号掩码非线程安全函数的安全化改造pthread_key_create创建线程持有数据关联的键值pthread_key_delete删除线程持有数据关联的键值pthread_setspecific设置键关联的线程持有数据pthread_getspecific获取键关联的线程持有数据11.2创建新进程创建新进程

自Linux内核2.0起,内核引入了clone系统调用,实现了对内核线程的初步支持,使用该系统调用可定制新的进程,其功能随着Linux的发展不断完善,glibc中的线程库正是基于该系统调用构建。创建子进程头文件

#define_GNU_SOURCE #include<sched.h>函数原型

int

clone(int(*fn)(void*),void*child_stack,intflags,void*arg…/*pid_t*ptid,void*newtls,pid_t*ctid*/);功能 创建新的进程。参数

fn:函数地址。

child_stack:栈地址。

flags:共享创建者进程的方式。

arg:指向传递的参数。返回值 成功返回线程的PID,失败返回-1。11.3线程控制线程属性

线程拥有诸多属性,例如,栈和信号掩码等,在创建线程前,根据特定的应用场景,应对其中部分属性进行设置。1.初始化/注销线程属性对象。2.获取/设置线程栈。3.获取/设置线程的分离属性。初始化/注销线程属性对象头文件

#include<pthread.h>函数原型 int

pthread_attr_init(pthread_attr_t*attr);

int

pthread_attr_destroy(pthread_attr_t*attr);功能 初始化/注销线程属性对象。参数

attr:线程属性对象。返回值 成功返回0,失败返回-1非0设置线程栈头文件

#include<pthread.h>函数原型

int

pthread_attr_getstack(pthread_attr_t*attr,void**addr,size_t*size);

int

pthread_attr_setstack(pthread_attr_t*attr,void*addr,size_tsize);功能 获取/设置线程栈。参数

attr:线程属性对象。

addr:线程栈地址。

size:线程栈大小。返回值 成功返回0,失败返回非0。设置线程的分离属性头文件

#include<pthread.h>函数原型

int

pthread_attr_getdetachstate(pthread_attr_t*attr,int*state);

int

pthread_attr_setdetachstate(pthread_attr_t*attr,intstate);功能 获取/设置线程的分离属性。参数

attr:线程的属性对象。

state:状态标志。返回值 成功返回0,失败返回非0。创建线程头文件

#include<pthread.h>函数原型

int

pthread_create(pthread_t*tid,pthread_attr_t*attr,void*(*start)(void*),void*args);功能 创建线程。参数

tid:线程ID。

attr:线程的属性。

start:线程执行的开始地址。

args:传递的参数。返回值

pthread_create函数成功返回0,失败返回错误代码。等待线程结束头文件

#include<pthread.h>函数原型

int

pthread_join(pthread_t

tid,void**status)功能 等待线程结束。参数

tid:线程ID。

status:线程的返回状态。返回值 成功返回0,失败返回错误代码。结束线程头文件

#include<pthread.h>函数原型

voidpthread_exit(void*retval);功能 结束线程。参数

retval:返回状态。返回值 无返回。11.4线程取消内容提要线程取消概述创建线程取消点线程的取消状态和类型清理函数向线程发送取消请求线程取消概述

对于某些应用,有时需要取消正在运行的线程,为此,在线程的执行路径上引入取消点,并设置响应的处理函数,当需要取消线程运行时,可线程发送取消请求,当线运行至取消点时,将检查是否由取消请求到达,当有取消请求到达时,执行响应的处理函数并退出运行。测试取消请求头文件

#include<pthread.h>函数原型

voidpthread_testcancel(void);功能 测试线程的取消请求是否到达。参数 无参数。返回值 若取消请求已到达,结束线程,否则,立即返回。线程的取消状态和类型

线程的取消有启用和禁用两种状态,在禁用状态下,线程收到的取消请求将被阻塞直至状态被启用;在启用状态下,线程会对收到的取消请求进行处理,具体方式取决于线程取消的类型设置线程的取消状态头文件

#include<pthread.h>函数原型

int

pthread_setcancelstate(intstate,int*oldstate);功能 设置线程的取消状态。参数

state:取消状态。

oldstate:原有状态地址。返回值 成功返回0,失败返回错误代码。设置线程取消的处理类型头文件

#include<pthread.h>函数原型

int

pthread_setcanceltype(inttype,int*oldtype);功能 设置线程取消的处理类型参数

type:处理类型。

oldtype:原处理类型地址。返回值 成功,返回0,失败,返回错误代码。线程清理函数

清理函数是线程取消时执行的函数,执行线程结束前的清理工作,以便线程安全退出。例如,释放互斥锁,以免死锁的发生。

清理函数以栈的形式存放,通常,收到取消请求的线程在到达下一个取消点时,清理函数以后进先出的方式执行。设置清理函数pthread_cleanup_push/pthread_cleanup_pop函数头文件

#include<pthread.h>函数原型

voidpthread_cleanup_push(void(*routine)(void*),void*arg); voidpthread_cleanup_pop(intexecute);功能 注册/注销线程清理函数。参数

routine:线程清理函数地址。

arg:传递的参数。

execute:执行标志。返回值 无返回值。发送取消请求pthread_cancel函数头文件

#include<pthread.h>函数原型

int

pthread_cancel(pthread_tthread);功能 向线程发送取消请求。参数

thread:线程ID。返回值 成功返回0,失败返回错误代码。11.5线程同步互斥锁

互斥锁是一种管理临界区访问的同步控制机制,确保同一时间段仅有一个线程访问临界区、线程访问临界区前,需申请互斥锁,只有获得互斥锁的线程允许进入临界区,未获得互斥锁的线程进入等待状态,直至获得释放的互斥锁。互斥锁的初始化头文件

#include<pthread.h>函数原型

pthread_mutex_t

mutex=PTHREAD_MUTEX_INITIALIZER;

int

pthread_mutex_init(pthread_mutex_t*mp,pthread_mutexattr_t*mattr)

int

pthread_mutex_destroy(pthread_mutex_t*mp)功能 初始化/注销互斥锁。参数

mp:互斥锁。

mattr:互斥锁属性。返回值 成功,返回0,失败,返回错误代码。申请/释放互斥锁pthread_mutex_lock/pthread_mutex_unlock函数头文件

#include<pthread.h>函数原型

int

pthread_mutex_lock(pthread_mutex_t*mp)

int

pthread_mutex_unlock(pthread_mutex_t*mp)功能 申请/释放互斥锁。参数

mp:互斥锁。返回值 成功返回0,失败返回错误代码。条件变量

条件变量是一种线程间基于条件的协调机制。,以条件变量的形式表示某种条件。当线程访问的条件不成立,线程将在条件变量上等待,直至条件得到满足。条件变量的相关函数属于非信号安全函数。初始化条件变量(1)pthread_cond_t

cond=PTHREAD_COND_INITIALIZER;//静态条件变量初始化(2)pthread_cond_init/pthread_cond_destroy函数头文件

#include<pthread.h>函数原型

int

pthread_cond_init(pthread_cond_t*cv,pthread_condattr_t*cattr)

int

pthread_cond_destroy(pthread_cond_t*cv)功能 初始化/注销条件变量。参数

cv:条件变量。

cattr:条件变量属性。返回值 成功返回0,失败返回错误代码。等待/释放条件变量thread_cond_wait/pthread_cond_signal函数头文件

#include<pthread.h>函数原型

int

pthread_cond_wait(pthread_cond_t*cv,pthread_mutex_t*mutex)

int

pthread_cond_signal(pthread_cond_t*cv)

int

pthread_cond_broadcast(pthread_cond_t*cv)功能 等待/释放条件变量参数

cv:条件变量。

mutex:互斥锁。返回值 成功返回0,失败返回错误代码。11.6多线程环境下的信号处理内容提要多线程环境下的信号线程的信号掩码多线程环境下的信号处理多线程环境下的信号

线程共享所属进程的信号处理方式,信号可发送至进程或进程中的某个线程。对于面向进程的信号,信号被进程中所有线程共享,进程中任意线程可对信号进行处理,具体的执行线程取决于调度时机;对于面向线程的信号,仅由目标线程处理。线程的信号掩码

线程有独立的信号掩码,线程的信号掩码继承自创建者进程。信号掩码为若干信号构成的集合,用于定义阻塞的信号。设置线程的信号掩码1.pthread_sigmask函数头文件

#include<signal.h>函数原型

int

pthread_sigmask(inthow,constsigset_t*set,sigset_t*oldset);功能 设置线程的信号掩码参数

how:操作方式。

set:新信号掩码地址。

oldset:原信号掩码地址。向线程发送信号pthread_kill/pthread_sigqueue函数头文件

#include<signal.h>函数原型

int

pthread_kill(pthread_t

tid,int

sig);

int

pthread_sigqueue(pthread_t

tid,int

sig,constunionsigvalvalue);功能 向线程发送信号。参数

tid:线程ID。

Sig:信号编号。

Value:传递的数据。返回值 成功返回0,失败返回错误代码。多线程环境下的信号处理

由于线程与信号的异步特性,为简化多线程环境下的信号处理,仅指定一个线程以同步方式处理到达的信号。将其他信号设置为阻塞状态。该处理方式可避免线程与信号处理程序间的资源竞争,从而降低程序设计的复杂性,提高程序的可读性和可靠性。11.7非线程安全函数的改造内容提要线程安全函数非线程安全函数非线程安全函数的改造线程的设计原则线程安全函数

当函数被多个线程同时调用时,若总能保证程序运行的正确性,则函数称为线程安全函数。若函数及其引用的子函数未使用全局变量或静态变量,则函数称为可重入函数。可重入函数一定是信号安全函数,反之,未必成立。对于函数中引用的全局变量或静态变量,若使用互斥锁进行了控制,则也可使函数称为信号安全的,非线程安全函数

当函数被多个线程同时调用时,若不能始终保持其正确性,则函数称为非信号安全函数。

glibc中的某些函数由于编写时间较早,诞生于线程出现之前,并未考虑多线程环境,有些函数的参数或返回值使用了全局变量或静态变量,因此,它们为非线程安全函数。例如,ctime和readdir函数等。非线程安全函数strerror非线程安全函数的改造

非线程安全函数的安全化改造就是指在功能和接口不变的前提下,将其转变为线程安全的函数,具体做法是将函数中的全局变量替换为线程持有变量,使每个线程拥有一份拷贝,以防止竞争现象的发生。根据转换方法的不同,可进一步划分为:1.线程持有数据2.线程局部存储

线程持有数据

对于非线程安全函数中的全局/静态变量,为每个线程创建一份称为线程持有数据的拷贝,以避免资源竞争的发生。

POSIX提供了一系列接口函数,为每个全局/静态变量创建一个以键值关联的数组,数组以线程ID为索引存放线程持有的数据。初始化实例(1)pthread_once函数头文件

#include<pthread.h>函数原型

int

pthread_once(pthread_once_t*once_control,void(*init_routine)(void));功能 仅初始化一次。参数

once_control:一次性控制变量。

init_routine:初始化函数地址。返回值 返回0。创建/删除线程持有数据关联的键值(2)pthread_key_create/pthread_key_delete函数头文件

#include<pthread.h>函数原型

int

pthread_key_create(pthread_key_t*key,void(*destr_function)(void*));

int

pthread_key_delete(pthread_key_tkey);功能 创建/删除键值。参数

Key:键值。

destr_function:析构函数。返回值 成功,返回0,失败,返回非0。获取/设置键值关联的线程持有数据(3)pthread_getspecific/pthread_setspecific函数头文件

#include<pthread.h>函数原型

void*pthread_getspecific(pthread_key_tkey);

int

pthread_setspecific(pthread_key_tkey,constvoid*pointer);功能 获取/设置键值关联的线程持有数据。参数

Key:键值。

pointer:线程持有数据地址。返回值

pthread_setspecific成功返回0,失败返回非0。基于线程持有数据的安全化改造staticpthread_once_tonce=PTHREAD_ONCE_INIT;staticpthread_key_t

strerrorKey;voidbuffer_destroy(void*buf){

free(buf);}voidbuffer_key_alloc(void){

ints; s=pthread_key_create(&strerrorKey,buffer_destroy); if(s!=0) err(1,"pthread_key_createfailed\n");}char*strerror(int

nerr){

ints; char*buf; s=pthread_once(&once,buffer_key_alloc); if(s!=0) err(1,"pthread_oncefailed\

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论