Linux多线程编程-.pdf





《Linux多线程编程-.pdf》由会员分享,可在线阅读,更多相关《Linux多线程编程-.pdf(22页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、第八章嵌入式 Linux 多线程编程8.1 线程基本概念8.1.1 Linux线程简介Linux 中的线程是轻量级线程(lightweight thread),Linux 中的线程调度是由内核调度程序完成的,每个线程有自己的ID 号。与进程相比,它们消耗的系统资源较少、创建较快、相互间的通信也较容易。存在于同一进程中的线程会共享一些信息,这些信息包括全局变量、进程指令、大部分数据、信号处理程序和信号设置、打开的文件、当前工作的目录以及用户ID 和用户组ID。同时作为一个独立的线程,它们又拥 有一些 区别 于其他 线程的信息,包括线程 ID、寄存器集合(如程序 计数器和堆栈 指针)、堆栈、错误
2、号、信号 掩码 以及线程 优先权。Linux 线程分为 两类:一是核 心级支持 线程。在核 心 级实现 线程时,线程的实现依赖 于内核。无论 是在用户进程中的线程还 是系统进程中的线程,它们的创建、撤销、切换都 由内核实现。内核 感知 线程的存在 并对其 进 行控制,并且允许不 同进程 里的线程 按照 同一相 对优先方法 调度,这适合 于 发挥多 处理 器的 并发优点。当某一个线程 发生阻塞 时,阻塞 的是 该 线程本身,线程 所在进程中的 其它线程 依然可 以参加 线程调度。在用户级 实现 线程时,没有核心支持 的多线程进程。因此,核心只 有单 线程进程 概念,而多 线程进程由与应用程序 连
3、接 的过程 库实现。核心不知道 线程的存在也就不能 独立的调度这些线程了。如果 一个线程调用了一个 阻塞 的系统调用,进程 可能被阻塞,当然其 中的 所 有线程也同时 被阻塞。目前 Linux 众多的线程 库中大部分 实现 的是用户级的线程,只有一些用于 研究 的线程 库才 尝试 实现 核心 级线程。系统创建线程如下:当一个进程 启动后,它会自 动创建一个线程 即主 线程(main thread)或者初始化 线程(initial thread),然后就利用 pthread_initialize()初始化 系统 管理线程 并且 启动线 程 机 制。线程 机 制 启 动后,要 创建 线 程 必 须
4、让pthread_create()向 管 理 线 程 发 送REQ_CREATE 请求,管 理线程 即 调用pthread_handle_create()创建 新线程。分 配栈、设置thread 属性后,以pthread_sart_thread()为 函 数 入口 调用 _clone()创建 并 启动新线程。pthread_start_thread()读取 自身的进程id 号存 入线程 描述结构 中,并根据 其中记录的调度 方法配 置调度。一切 准备 就 绪后,再 调用 真正 的线程 执 行 函数,并 在 此 函 数 返回后 调用pthread_exit()清理现场。8.1.2 Linux线程
5、编程基础相对进程 而言,线程 更加接 近于 执行体,它可以与同进程中的其他 线程共享数据,且拥PDF 文件使用 pdfFactory Pro 试用版本创建 有自己的 栈,拥有独立的 执行序列。在串行 程序 基础上引入 线程和进程是为了提高 程序的 并发度,从而提高 程序 运行效率 和响 应时间。现在我们通 过 一个 简单的例子来介绍 一下 Linux 下的多线程 编程:#include stdio.h#include pthread.hvoid myfirstthread(void)int i;for(i=0;i 3;i+)printf(This is my thread.n);int mai
6、n(void)pthread_t id;int i,ret;ret=pthread_create(&id,NULL,(void*)myfirstthread,NULL);if(ret!=0)printf(Create pthread error!n);exit(1);for(i=0;i 3;i+)printf(This is the main process.n);pthread_join(id,NULL);return(0);要创建一个 多 线程程序,必须 加载 pthread.h 文件。线程的标识符pthread_t 在头文件/usr/include/bits/pthreadtypes.h
7、 中定义:typedef unsigned long int pthread_t。现在我们介绍 一下多线程 编程常用的 几个函数:npthread_create()函 数函数 pthread_create()创建一个 新的线程 并把它的 标识符放入 参数 thread 指向的新线程中。API 定义 如下:#include int pthread_create(pthread_t*thread,pthread_attr_t*attr,void*(*start_routine)(void*),void*arg)PDF 文件使用 pdfFactory Pro 试用版本创建 第二 个参数 attr 是
8、用 来设置线程的 属性。线程的 属性 是由 函数 pthread_attr_init()来生成。第三 个参数是 新线程 要执 行的函数的 地址。第四 个 参数是一个void 指针,可以作为 任意 类型的 参数传给 start_routine()函数;同时,start_routine()可 以返回 一个 void*类型的返回 值,而这个 返回 值也可 以是 其他类 型,并由 pthread_join()获取。npthread_join()函数函数 pthread_join()的作用是 挂起 当前线程 直到 参数 th 指定的线程 被终止 为止。API 定义如 下:#include int pth
9、read_join(pthread_t th,void*thread_return);int pthread_detach(pthread_t th);第一个 参数 th 为被等待 的线程 标识符,第二 个参数为一个用户 定义 的指 针,它 可以用来存 储被等待 线程的 返回 值。这个 函数是一个线程阻塞 的函数,调用它的 函数将一直等待到被等待 的线程 结束 为止,当函数返回 时,被等待 线程的资源 被收回。一个线程的 结束有两 种途径,一种是象我们 上面的例子 一样,函数结束了,调用它的线程也就结束了;另一种方 式是通 过函数 pthread_exit 来实现。npthread_exit(
10、)函 数该函 数调用 pthread_cleanup_push()为线程 注册 的清除 处理 函数,然后结 束当前线程,返回 retval,父线程 或其它线程 可以通 过函 数 pthread_join()来检索 它。API 定义 为:#include void pthread_exit(void*retval)n属性 控制在 上述 的例子 中,我们用 pthread_create()函数创建 了 一个线程,在这个线程中,我们 使用了 默认 参数,即将该函数的 第二 个参数设为 NULL。对大多数程序 来说使用默认 属性 足够,但我 们仍然需要了 解一下线程的 属性。属性结构 为 pthrea
11、d_attr_t,它同 样在头 文件/usr/include/pthread.h 中定义,属性 值不能 直接设置,须使 用相 关函数进 行操作。函数 pthread_attr_init()的作用是 初始化 一个 新的属性 对象,函数 pthread_attr_destroy()的作用是 清除 属性 对象。用户在调用这些函 数之前要为属性(attr)对象分配空间。#include int pthread_attr_init(pthread_attr_t*attr);int pthread_attr_destroy(pthread_attr_t*attr);int pthread_attr_set
12、detachstate(pthread_attr_t*attr,int detachstate);int pthread_attr_getdetachstate(const pthread_attr_t*attr,int*detachstate);int pthread_attr_setschedpolicy(pthread_attr_t*attr,int policy);int pthread_attr_getschedpolicy(const pthread_attr_t*attr,int*policy);int pthread_attr_setschedparam(pthread_att
13、r_t*attr,const struct sched_param*param);int pthread_attr_getschedparam(const pthread_attr_t*attr,struct sched_param*param);PDF 文件使用 pdfFactory Pro 试用版本创建 int pthread_attr_setscope(pthread_attr_t*attr,int scope);int pthread_attr_getscope(const pthread_attr_t*attr,int*scope);关于线程的 绑 定,牵涉到另外 一个 概念:轻进程
14、(LWP:Light Weight Process)。轻进程可 以理 解为内核线程,它位于用户 层 和系统 层之 间。系统 对线程资源的分配、对线程的 控制是通 过轻进程 来 实现 的,一个轻进程 可以控制 一个 或 多个线程。默认状况 下,启动 多少轻进程、哪些轻进程 来控制 哪些线程是由系统来控制 的,这 种状况 即称为非绑 定的。绑定状况下,则顾名思 义,即某 个线程 固定的绑在一个轻进程之 上。被绑定的线程 具有较 高的响 应速度,这是 因为 CPU 时间 片的调度是 面向 轻进程的,绑定 的线程 可以保证 在需要的时 候 它总有一个轻进程可 用。通过 设置 被绑定的轻进程的 优先 级
15、和调度级 可以使得绑 定的线程 满足诸如实 时反应之类 的要求。设置线程 绑 定状态 的函数为pthread_attr_setscope(),它有 两个 参数,第 一 个 是 指 向 属 性 结 构 的 指 针,第 二 个 是 绑 定 类 型,它 有 两 个 取 值:PTHREAD_SCOPE_SYSTEM(绑 定的)和 PTHREAD_SCOPE_PROCESS(非绑 定的)。线程的分 离状态决 定一个线程以 什么样 的 方式 来终止 自己。在 上面的 例子 中,我们 采用了 线程的 默认 属性,即为非分离状态,这种情况 下,原 有的线程 等待 创建的线程 结束。只有当pthread_joi
16、n()函数 返回 时,创建的线程才算终止,才能 释放自己 占 用的系统资源。而分 离线程 不是这 样子的,它没有被其他 的线程 所等待,自己 运行结束了,线程也 就 终止 了,马上 释放系统资源。程序 员应该 根据自己的 需要,选择 适 当的分 离状态。设置线程分 离状态的函 数为pthread_attr_setdetachstate(pthread_attr_t*attr,int detachstate)。第二 个参数可选 为PTHREAD_CREATE_DETACHED(分离 线程)和 PTHREAD _CREA TE_JOINABLE(非 分离线程)。这里 要注意 的一 点是,如果 设置
17、一个线程为分离线程,而这个线程 运行又 非常快,它很 可能 在 pthread_create函数返回 之前就 终止 了,它终止 以后就可能 将线程号和系统资源移交给 其他 的线程 使用,这 样调用 pthread_create 的线程 就 得到 了错误 的线程号。要避免 这种情况 可 以 采 取 一 定 的同 步措施,最 简 单 的 方法 之 一是 可 以在 被 创建的线程里 调用pthread_cond_timewait 函 数,让这个线程 等待 一会 儿,留出 足够 的时间 让函 数 pthread_create返回。设置一 段等待 时间,是在 多 线程 编程里常用的 方法。但是注意 不要
18、使 用诸如 wait()之类 的函数,它们是 使整个进程 睡眠,并不能 解决 线程同 步的问题。线程 优先 级存 放在结构sched_param 中。用 函 数 pthread_attr_getschedparam()和函 数pthread_attr_setschedparam()进行存放,一般说来,我们总 是先取优先 级,对 取得的值修改 后再存 放回 去。它们的 第 一个 参数用于 标识要 操作的线程,第二 个参数是线程的调度策略,第三个 参数是指 向调度 参数的指 针。n取消线程可在当前线程中通过调用 函数 pthread_cancle()来取 消另一个线程,该线程由 参数 thread
19、指定。#include int pthread_cancel(pthread_t thread);int pthread_setcancelstate(int state,int*oldstate);int pthread_setcanceltype(int type,int*oldtype);PDF 文件使用 pdfFactory Pro 试用版本创建 void pthread_testcancel(void);线程调用pthread_setcancelstate()设置自己的 取消 状态,参数 state是新 状态,参数 oldstate是一个指 针,指向存 放旧状态 的变量(如果不 为空
20、)函 数 pthread_setcanceltype()修改 响应 取消请求 的类型,响 应的类型有两种:PTHREAD_CANCEL_ASYNCHRONOUS 线程 被立即取 消PTHREAD_CANCEL_DEFERRED 延迟 取消至取消点取消点是通 过 调用 pthread_testcancel()来创建,如果 延迟 取消请求 挂起,那么该函数 将取消当前线程。前三个函数成 功时 返回 0,失败 时返回 错误 代码。npthread_cond_init()函数下列函 数作用是 挂起 当前线程 直到满足 某种条 件。#include pthread_cond_t cond=PTHREAD
21、_COND_INITIALIZER int pthread_cond_init(pthread_cond_t*cond,pthread_condattr_t*cond_attr);int pthread_cond_signal(pthread_cond_t*cond);int pthread_cond_broadcast(pthread_cond_t*cond);int pthread_cond_wait(pthread_cond_t*cond,pthread_mutex_t*mutex);int pthread_cond_timedwait(pthread_cond_t*cond,pthre
22、ad_mutex_t*mutex,const struct timespec*abstime);int pthread_cond_destroy(pthread_cond_t*cond);函数 pthread_cond_init()初始化 一个 pthread_cond_t 类型的对象 cond。在 Linux 中它的 第二 个 参 数 被 忽 略,可 以 简 单 的 用PTHREAD_COND_INITIALIZER替 换。pthread_cond_destroy()是 cond 对象的 析构函 数,它仅检 查是否还有线程在 等待 该条件。函 数pthread_cond_signal()重启
23、动 一个 等待 某种条件的线程。pthread_cond_broadcast()重启动 所 有的线程。函数 pthread_cond_wait()对一个互 斥量进 行 解锁,并且 等待 条件变量 cond 中的信号。pthread_cond_timedwait()函数作用与pthread_cond_wait()相似,不过 它只等待 一段 由 abstime指定 的时间。n互斥互斥锁 用来 保证 一段时间内 只有一个线程在执行一段代 码。必要性 显 而易见:假 设各个线程 向同一个文件 顺序写入数据,最后得到 的结 果一定是灾难 性 的。API 定义 如下:#include pthread_mu
24、tex_t fastmutex=PTHREAD_MUTEX_INITIALIZER;pthread_mutex_t recmutex=PTHREAD_RECURSIVE_MUTEX_ INITIALIZER_NP;pthread_mutex_t errchkmutex=PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;int pthread_mutex_init(pthread_mutex_t*mutex,const pthread_mutexattr_t*mutexattr);int pthread_mutex_lock(pthread_mutex_t*mute
25、x);int pthread_mutex_trylock(pthread_mutex_t*mutex);int pthread_mutex_unlock(pthread_mutex_t*mutex);PDF 文件使用 pdfFactory Pro 试用版本创建 int pthread_mutex_destroy(pthread_mutex_t*mutex);函数 pthread_mutex_init()和 pthread_mutex_destroy()分 别是互 斥锁 的 构造函数和 析构函数。函 数pthread_mutex_lock()和pthread_mutex_unlock()分 别
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Linux 多线程 编程

限制150内