没有合适的资源?快使用搜索试试~ 我知道了~
首页由浅入深Linux下pthread线程库介绍
由浅入深Linux下pthread线程库介绍
5星 · 超过95%的资源 需积分: 10 131 下载量 43 浏览量
更新于2023-03-03
评论 1
收藏 59KB DOC 举报
详细介绍了Linux下pthread线程库,并对线程创建与结束、线程的绑定、线程的状态、线程的优先级、线程的撤消、线程数据、互斥锁、条件变量、信号量、异步信号等都有详细的说明,并附有例子,帮助读者由浅入深的了解Linux下pthread线程库
资源详情
资源评论
资源推荐
Linux 下 pthread 线程库介绍
1、概述
多线程程序作为一种多任务、并发的工作方式,有以下的优点:
1) 提高应用程序响应。这对图形界面的程序尤其有意义,当一个操作耗时很长时,整个系统都会等待这
个操作,此时程序不会响应键盘、鼠标、菜单的操作,而使用多线程技术,将耗时长的操作(time
consuming)置于一个新的线程,可以避免这种尴尬的情况。
2) 使多 CPU 系统更加有效。操作系统会保证当线程数不大于 CPU 数目时,不同的线程运行于不同的
CPU 上。
3) 改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,
这样的程序会利于理解和修改。
Linux 下最常用的是遵循 POSIX 标准的 pthread 线程库。pthread 的实现是通过系统调用 clone()这一
Linux 特有的系统调用来实现。
2、线程创建与结束
1)pthread_t
线程的标识符类型,pthread_t 在头文件/usr/include/bits/pthreadtypes.h 中定义:
typedef unsigned long int pthread_t;
2)pthread_create
thread_create 用来创建一个线程,它的原型为:
extern int pthread_create __P ((pthread_t *__thread, __const pthread_attr_t *__attr,
void *(*__start_routine) (void *), void *__arg));
第一个参数为指向线程标识符的指针,第二个参数用来设置线程属性,第三个参数是线程运行函数的起始
地址,最后一个参数是运行函数的参数。这里,我们的函数 thread 不需要参数,所以最后一个参数设为
空指针。第二个参数我们也设为空指针,这样将生成默认属性的线程。对线程属性的设定和修改我们将在
下一节阐述。当创建线程成功时,函数返回 0,若不为 0 则说明创建线程失败,常见的错误返回代码为
EAGAIN 和 EINVAL。前者表示系统限制创建新的线程,例如线程数目过多了;后者表示第二个参数代表
的线程属性值非法。创建线程成功后,新创建的线程则运行参数三和参数四确定的函数,原来的线程则继
续运行下一行代码。
3)pthread_join
函数 pthread_join 用来等待一个线程的结束。函数原型为:
extern int pthread_join __P ((pthread_t __th, void **__thread_return));
第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,它可以用来存储被等待线程的返
回值。这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回
时,被等待线程的资源被收回。
4)pthread_exit
线程除了正常执行结束外,还可以通过函数 pthread_exit 来结束它,pthread_exit 的函数原型为:
extern void pthread_exit __P ((void *__retval)) __attribute__ ((__noreturn__));
唯一的参数是函数的返回代码,只要 pthread_join 中的第二个参数 thread_return 不是 NULL,这个值将被
传递给 thread_return。最后要说明的是,一个线程不能被多个线程等待,否则第一个接收到信号的线程
成功返回,其余调用 pthread_join 的线程则返回错误代码 ESRCH。
3 修改线程的属性
属性结构为 pthread_attr_t,在头文件 /usr/include/pthread.h 中定义。属性值不能直接设置,须使用相关
函数进行操作,初始化的函数为 pthread_attr_init,这个函数必须在 pthread_create 函数之前调用。属性
对象主要包括是否绑定、是否分离、堆栈地址、堆栈大小、优先级。默认的属性为非绑定、非分离、缺省
1M 的堆栈、与父进程同样级别的优先级。
1) 关于线程的绑定
线程的绑定,牵涉到另外一个概念:轻进程(LWP:Light Weight Process)。轻进程可以理解为内核线
程,它位于用户层和系统层之间。系统对线程资源的分配、对线程的控制是通过轻进程来实现的,一个轻
进程可以控制一个或多个线程。默认状况下,启动多少轻进程、哪些轻进程来控制哪些线程是由系统来控
制的,这种状况即称为非绑定的。绑定状况下,则顾名思义,即某个线程固定的"绑"在一个轻进程之上。
被绑定的线程具有较高的响应速度,这是因为 CPU 时间片的调度是面向轻进程的,绑定的线程可以保证
在需要的时候它总有一个轻进程可用。通过设置被绑定的轻进程的优先级和调度级可以使得绑定的线程满
足诸如实时反应之类的要求。
设置线程绑定状态的函数为 pthread_attr_setscope,它有两个参数,第一个是指向属性结构的指针,第
二个是绑定类型,它有两个取值: PTHREAD_SCOPE_SYSTEM(绑定的)和
PTHREAD_SCOPE_PROCESS(非绑定的)。下面的代码即创建了一个绑定的线程。
#include
pthread_attr_t attr;
pthread_t tid;
/*初始化属性值,均设为默认值*/
pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
pthread_create(&tid, &attr, (void *) my_function, NULL);
2)关于线程的状态:分离态/非分离态
线程的分离状态决定一个线程以什么样的方式来终止自己。在上面的例子中,我们采用了线程的默认属性,
即为非分离状态,这种情况下,原有的线程等待创建的线程结束。只有当 pthread_join()函数返回时,
创建的线程才算终止,才能释放自己占用的系统资源。而分离线程不是这样子的,它没有被其他的线程所
等待,自己运行结束了,线程也就终止了,马上释放系统资源。程序员应该根据自己的需要,选择适当的
分离状态。设置线程分离状态的函数为
pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
第二个参数可选为 PTHREAD_CREATE_DETACHED(分离线程)和 PTHREAD
_CREATE_JOINABLE(非分离线程)。这里要注意的一点是,如果设置一个线程为分离线程,而这个线
程运行又非常快,它很可能在 pthread_create 函数返回之前就终止了,它终止以后就可能将线程号和系
统资源移交给其他的线程使用,这样调用 pthread_create 的线程就得到了错误的线程号。要避免这种情况
可以采取一定的同步措施,最简单的方法之一是可以在被创建的线程里调用 pthread_cond_timewait 函数,
让这个线程等待一会儿,留出足够的时间让函数 pthread_create 返回。设置一段等待时间,是在多线程编
程里常用的方法。但是注意不要使用诸如 wait()之类的函数,它们是使整个进程睡眠,并不能解决线程
同步的问题。
3)关于线程的优先级
线程的优先级,它存放在结构 sched_param 中。用函数 pthread_attr_getschedparam 和函数
pthread_attr_setschedparam 进行存放,一般说来,我们总是先取优先级,对取得的值修改后再存放回去。
线程的优先级取值范围为-20~20,值越大,其优先级越低,缺省值为 0,这个参数仅当调度策略为实时
(即 SCHED_RR 或 SCHED_FIFO)时才有效,在运行时通过 pthread_setschedparam()函数来改变:
下面即是一段简单的例子。
#include
#include
pthread_attr_t attr;
pthread_t tid;
sched_param param;
int newprio=20;
pthread_attr_init(&attr);
pthread_attr_getschedparam(&attr, ¶m);
param.sched_priority=newprio;
pthread_attr_setschedparam(&attr, ¶m);
pthread_create(&tid, &attr, (void *)myfunction, myarg);
4 线程的数据处理
和进程相比,线程的最大优点之一是数据的共享性,各个进程共享父进程处沿袭的数据段,可以方便的获
得、修改数据。但这也给多线程编程带来了许多问题。我们必须当心有多个不同的进程访问相同的变量。
许多函数是不可重入的,即同时不能运行一个函数的多个拷贝(除非使用不同的数据段)。在函数中声明
的静态变量常常带来问题,函数的返回值也会有问题。因为如果返回的是函数内部静态声明的空间的地址,
则在一个线程调用该函数得到地址后使用该地址指向的数据时,别的线程可能调用此函数并修改了这一段
数据。在进程党国享的变量必须用关键字 volatile 来定义,这是为了防止编译器在优化时(如 gcc 中使用-
OX 参数)改变它们的使用方式。为了保护变量,我们必须使用信号量、互斥等方法来保证我们对变量的
正确使用。
1) 线程数据
在单线程的程序里,有两种基本的数据:全局变量和局部变量。但在多线程程序里,还有第三种数据类型:
线程数据(TSD: Thread-Specific Data)。它和全局变量很象,在线程内部,各个函数可以象使用全局变
量一样调用它,但它对线程外部的其它线程是不可见的。这种数据的必要性是显而易见的。例如我们常见
的变量 errno,它返回标准的出错信息。它显然不能是一个局部变量,几乎每个函数都应该可以调用它;
但它又不能是一个全局变量,否则在 A 线程里输出的很可能是 B 线程的出错信息。要实现诸如此类的变
量,我们就必须使用线程数据。我们为每个线程数据创建一个键,它和这个键相关联,在各个线程里,都
使用这个键来指代线程数据,但在不同的线程里,这个键代表的数据是不同的,在同一个线程里,它代表
同样的数据内容。
和线程数据相关的函数主要有 4 个:创建一个键;为一个键指定线程数据;从一个键读取线程数据;删除
键。
创建键的函数原型为:
extern int pthread_key_create __P ((pthread_key_t *__key,void (*__destr_function) (void *)));
第一个参数为指向一个键值的指针,第二个参数指明了一个 destructor 函数,如果这个参数不为空,那么
当每个线程结束时,系统将调用这个函数来释放绑定在这个键上的内存块。这个函数常和函数
pthread_once ((pthread_once_t*once_control, void (*initroutine) (void)))一起使用,为了让这个键只被创
建一次。函数 pthread_once 声明一个初始化函数,第一次调用 pthread_once 时它执行这个函数,以后的
调用将被它忽略。
在下面的例子中,我们创建一个键,并将它和某个数据相关联。我们要定义一个函数 createWindow,这
个函数定义一个图形窗口(数据类型为 Fl_Window *,这是图形界面开发工具 FLTK 中的数据类型)。由
于各个线程都会调用这个函数,所以我们使用线程数据。
/* 声明一个键*/
pthread_key_t myWinKey;
/* 函数 createWindow */
void createWindow ( void ) {
Fl_Window * win;
剩余10页未读,继续阅读
mageko
- 粉丝: 0
- 资源: 8
上传资源 快速赚钱
- 我的内容管理 收起
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
会员权益专享
最新资源
- c++校园超市商品信息管理系统课程设计说明书(含源代码) (2).pdf
- 建筑供配电系统相关课件.pptx
- 企业管理规章制度及管理模式.doc
- vb打开摄像头.doc
- 云计算-可信计算中认证协议改进方案.pdf
- [详细完整版]单片机编程4.ppt
- c语言常用算法.pdf
- c++经典程序代码大全.pdf
- 单片机数字时钟资料.doc
- 11项目管理前沿1.0.pptx
- 基于ssm的“魅力”繁峙宣传网站的设计与实现论文.doc
- 智慧交通综合解决方案.pptx
- 建筑防潮设计-PowerPointPresentati.pptx
- SPC统计过程控制程序.pptx
- SPC统计方法基础知识.pptx
- MW全能培训汽轮机调节保安系统PPT教学课件.pptx
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论9