欢迎来到淘文阁 - 分享文档赚钱的网站! | 帮助中心 好文档才是您的得力助手!
淘文阁 - 分享文档赚钱的网站
全部分类
  • 研究报告>
  • 管理文献>
  • 标准材料>
  • 技术资料>
  • 教育专区>
  • 应用文书>
  • 生活休闲>
  • 考试试题>
  • pptx模板>
  • 工商注册>
  • 期刊短文>
  • 图片设计>
  • ImageVerifierCode 换一换

    Linux多线程编程-.pdf

    • 资源ID:76261075       资源大小:204.49KB        全文页数:22页
    • 资源格式: PDF        下载积分:20金币
    快捷下载 游客一键下载
    会员登录下载
    微信登录下载
    三方登录下载: 微信开放平台登录   QQ登录  
    二维码
    微信扫一扫登录
    下载资源需要20金币
    邮箱/手机:
    温馨提示:
    快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。
    如填写123,账号就是123,密码也是123。
    支付方式: 支付宝    微信支付   
    验证码:   换一换

     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    Linux多线程编程-.pdf

    第八章嵌入式 Linux 多线程编程8.1 线程基本概念8.1.1 Linux线程简介Linux 中的线程是轻量级线程(lightweight thread),Linux 中的线程调度是由内核调度程序完成的,每个线程有自己的ID 号。与进程相比,它们消耗的系统资源较少、创建较快、相互间的通信也较容易。存在于同一进程中的线程会共享一些信息,这些信息包括全局变量、进程指令、大部分数据、信号处理程序和信号设置、打开的文件、当前工作的目录以及用户ID 和用户组ID。同时作为一个独立的线程,它们又拥 有一些 区别 于其他 线程的信息,包括线程 ID、寄存器集合(如程序 计数器和堆栈 指针)、堆栈、错误 号、信号 掩码 以及线程 优先权。Linux 线程分为 两类:一是核 心级支持 线程。在核 心 级实现 线程时,线程的实现依赖 于内核。无论 是在用户进程中的线程还 是系统进程中的线程,它们的创建、撤销、切换都 由内核实现。内核 感知 线程的存在 并对其 进 行控制,并且允许不 同进程 里的线程 按照 同一相 对优先方法 调度,这适合 于 发挥多 处理 器的 并发优点。当某一个线程 发生阻塞 时,阻塞 的是 该 线程本身,线程 所在进程中的 其它线程 依然可 以参加 线程调度。在用户级 实现 线程时,没有核心支持 的多线程进程。因此,核心只 有单 线程进程 概念,而多 线程进程由与应用程序 连接 的过程 库实现。核心不知道 线程的存在也就不能 独立的调度这些线程了。如果 一个线程调用了一个 阻塞 的系统调用,进程 可能被阻塞,当然其 中的 所 有线程也同时 被阻塞。目前 Linux 众多的线程 库中大部分 实现 的是用户级的线程,只有一些用于 研究 的线程 库才 尝试 实现 核心 级线程。系统创建线程如下:当一个进程 启动后,它会自 动创建一个线程 即主 线程(main thread)或者初始化 线程(initial thread),然后就利用 pthread_initialize()初始化 系统 管理线程 并且 启动线 程 机 制。线程 机 制 启 动后,要 创建 线 程 必 须让pthread_create()向 管 理 线 程 发 送REQ_CREATE 请求,管 理线程 即 调用pthread_handle_create()创建 新线程。分 配栈、设置thread 属性后,以pthread_sart_thread()为 函 数 入口 调用 _clone()创建 并 启动新线程。pthread_start_thread()读取 自身的进程id 号存 入线程 描述结构 中,并根据 其中记录的调度 方法配 置调度。一切 准备 就 绪后,再 调用 真正 的线程 执 行 函数,并 在 此 函 数 返回后 调用pthread_exit()清理现场。8.1.2 Linux线程编程基础相对进程 而言,线程 更加接 近于 执行体,它可以与同进程中的其他 线程共享数据,且拥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 main(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 中定义: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 是用 来设置线程的 属性。线程的 属性 是由 函数 pthread_attr_init()来生成。第三 个参数是 新线程 要执 行的函数的 地址。第四 个 参数是一个void 指针,可以作为 任意 类型的 参数传给 start_routine()函数;同时,start_routine()可 以返回 一个 void*类型的返回 值,而这个 返回 值也可 以是 其他类 型,并由 pthread_join()获取。npthread_join()函数函数 pthread_join()的作用是 挂起 当前线程 直到 参数 th 指定的线程 被终止 为止。API 定义如 下:#include int pthread_join(pthread_t th,void*thread_return);int pthread_detach(pthread_t th);第一个 参数 th 为被等待 的线程 标识符,第二 个参数为一个用户 定义 的指 针,它 可以用来存 储被等待 线程的 返回 值。这个 函数是一个线程阻塞 的函数,调用它的 函数将一直等待到被等待 的线程 结束 为止,当函数返回 时,被等待 线程的资源 被收回。一个线程的 结束有两 种途径,一种是象我们 上面的例子 一样,函数结束了,调用它的线程也就结束了;另一种方 式是通 过函数 pthread_exit 来实现。npthread_exit()函 数该函 数调用 pthread_cleanup_push()为线程 注册 的清除 处理 函数,然后结 束当前线程,返回 retval,父线程 或其它线程 可以通 过函 数 pthread_join()来检索 它。API 定义 为:#include void pthread_exit(void*retval)n属性 控制在 上述 的例子 中,我们用 pthread_create()函数创建 了 一个线程,在这个线程中,我们 使用了 默认 参数,即将该函数的 第二 个参数设为 NULL。对大多数程序 来说使用默认 属性 足够,但我 们仍然需要了 解一下线程的 属性。属性结构 为 pthread_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_setdetachstate(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_attr_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);关于线程的 绑 定,牵涉到另外 一个 概念:轻进程(LWP:Light Weight Process)。轻进程可 以理 解为内核线程,它位于用户 层 和系统 层之 间。系统 对线程资源的分配、对线程的 控制是通 过轻进程 来 实现 的,一个轻进程 可以控制 一个 或 多个线程。默认状况 下,启动 多少轻进程、哪些轻进程 来控制 哪些线程是由系统来控制 的,这 种状况 即称为非绑 定的。绑定状况下,则顾名思 义,即某 个线程 固定的绑在一个轻进程之 上。被绑定的线程 具有较 高的响 应速度,这是 因为 CPU 时间 片的调度是 面向 轻进程的,绑定 的线程 可以保证 在需要的时 候 它总有一个轻进程可 用。通过 设置 被绑定的轻进程的 优先 级和调度级 可以使得绑 定的线程 满足诸如实 时反应之类 的要求。设置线程 绑 定状态 的函数为pthread_attr_setscope(),它有 两个 参数,第 一 个 是 指 向 属 性 结 构 的 指 针,第 二 个 是 绑 定 类 型,它 有 两 个 取 值:PTHREAD_SCOPE_SYSTEM(绑 定的)和 PTHREAD_SCOPE_PROCESS(非绑 定的)。线程的分 离状态决 定一个线程以 什么样 的 方式 来终止 自己。在 上面的 例子 中,我们 采用了 线程的 默认 属性,即为非分离状态,这种情况 下,原 有的线程 等待 创建的线程 结束。只有当pthread_join()函数 返回 时,创建的线程才算终止,才能 释放自己 占 用的系统资源。而分 离线程 不是这 样子的,它没有被其他 的线程 所等待,自己 运行结束了,线程也 就 终止 了,马上 释放系统资源。程序 员应该 根据自己的 需要,选择 适 当的分 离状态。设置线程分 离状态的函 数为pthread_attr_setdetachstate(pthread_attr_t*attr,int detachstate)。第二 个参数可选 为PTHREAD_CREATE_DETACHED(分离 线程)和 PTHREAD _CREA TE_JOINABLE(非 分离线程)。这里 要注意 的一 点是,如果 设置一个线程为分离线程,而这个线程 运行又 非常快,它很 可能 在 pthread_create函数返回 之前就 终止 了,它终止 以后就可能 将线程号和系统资源移交给 其他 的线程 使用,这 样调用 pthread_create 的线程 就 得到 了错误 的线程号。要避免 这种情况 可 以 采 取 一 定 的同 步措施,最 简 单 的 方法 之 一是 可 以在 被 创建的线程里 调用pthread_cond_timewait 函 数,让这个线程 等待 一会 儿,留出 足够 的时间 让函 数 pthread_create返回。设置一 段等待 时间,是在 多 线程 编程里常用的 方法。但是注意 不要使 用诸如 wait()之类 的函数,它们是 使整个进程 睡眠,并不能 解决 线程同 步的问题。线程 优先 级存 放在结构sched_param 中。用 函 数 pthread_attr_getschedparam()和函 数pthread_attr_setschedparam()进行存放,一般说来,我们总 是先取优先 级,对 取得的值修改 后再存 放回 去。它们的 第 一个 参数用于 标识要 操作的线程,第二 个参数是线程的调度策略,第三个 参数是指 向调度 参数的指 针。n取消线程可在当前线程中通过调用 函数 pthread_cancle()来取 消另一个线程,该线程由 参数 thread指定。#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是一个指 针,指向存 放旧状态 的变量(如果不 为空)函 数 pthread_setcanceltype()修改 响应 取消请求 的类型,响 应的类型有两种:PTHREAD_CANCEL_ASYNCHRONOUS 线程 被立即取 消PTHREAD_CANCEL_DEFERRED 延迟 取消至取消点取消点是通 过 调用 pthread_testcancel()来创建,如果 延迟 取消请求 挂起,那么该函数 将取消当前线程。前三个函数成 功时 返回 0,失败 时返回 错误 代码。npthread_cond_init()函数下列函 数作用是 挂起 当前线程 直到满足 某种条 件。#include pthread_cond_t cond=PTHREAD_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,pthread_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()重启动 一个 等待 某种条件的线程。pthread_cond_broadcast()重启动 所 有的线程。函数 pthread_cond_wait()对一个互 斥量进 行 解锁,并且 等待 条件变量 cond 中的信号。pthread_cond_timedwait()函数作用与pthread_cond_wait()相似,不过 它只等待 一段 由 abstime指定 的时间。n互斥互斥锁 用来 保证 一段时间内 只有一个线程在执行一段代 码。必要性 显 而易见:假 设各个线程 向同一个文件 顺序写入数据,最后得到 的结 果一定是灾难 性 的。API 定义 如下:#include pthread_mutex_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*mutex);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()分 别 用 来 加 锁 和 解 锁。函 数pthread_mutex_trylock()和 pthread_mutex_lock()相 似,不同的是 pthread_mutex_trylock()只有在互 斥 被 锁住 的 情况 下 才阻塞。上述函 数在成 功时 返回0,失败 时返回 错误 代 码。但pthread_mutex_init()从不失败。8.2 多线程编程同步8.2.1 互斥锁当在同一内存空间运行多 个线程时,要注意 的一个 基本 问题 是不能 让 线程 之间相互 破坏。假如两 个线程 要更新 两个变量的 值。一个线程 要把 两个变量的 值 都设成 0,另一个线程要把 两个变量的 值 都设成 1。如果两 个线程同时 要同时 运行,每 次运行 的结果可能不 一 样。为解决 该问题,pthread 库提供了一种基 本机制,叫互斥量(mutex)。互斥量是 Mutual Exclusion device 的简称,它相当于一把锁,可以 保证 以下三 点l原子性:如果 一个线程 锁定了 一个互 斥量,那么 临界 区内的 操作 要么全部完成,要么一个也 不执行。l唯一性:如果 一个线程 锁定了 一个互 斥量,那么 在它 解除 锁定之 前,没有其它线程可以锁定 这个互 斥量。l非繁忙 等待:如果 一个线程 已经锁 定一个互 斥 量,第二 个线程 又 试图去锁 定这个互斥量,则 第二 个线程 将被 挂起(不占用 任何 CPU 资源),直到 第一个线程 解除 对这个互斥量的 锁定为止,第二 个线程 将被唤醒 并继续 执行,同时 锁定这个互 斥量。我们通 过下面 一段代 码来学习 互斥锁 的使用,这是一个读/写程序,它们 公用一个 缓冲区,并且 我们假定 一个 缓冲 区只能 保存一 条信息。即 缓冲 区只 有两个 状态:有信息 或 没有信息。void reader_function(void);void writer_function(void);char buffer;int buffer_has_item=0;pthread_mutex_t mutex;struct timespec delay;void main(void)pthread_t reader;/*定义 延迟 时间*/delay.tv_sec=2;PDF 文件使用 pdfFactory Pro 试用版本创建 delay.tv_nec=0;/*用默认 属性初始化 一个互 斥锁 对象*/pthread_mutex_init(&mutex,NULL);pthread_create(&reader,pthread_attr_default,(void*)&reader_function),NULL);writer_function();void writer_function(void)while(1)/*锁 定互斥锁*/pthread_mutex_lock(&mutex);if(buffer_has_item=0)buffer=make_new_item();buffer_has_item=1;/*打开互 斥锁*/pthread_mutex_unlock(&mutex);pthread_delay_np(&delay);void reader_function(void)while(1)pthread_mutex_lock(&mutex);if(buffer_has_item=1)consume_item(buffer);buffer_has_item=0;pthread_mutex_unlock(&mutex);pthread_delay_np(&delay);创建互 斥量时,必须 首先声明 一个 类型为 pthread_mutex_t 的变量,然后对其 进行初始化,结构 pthread_mutex_t 为不公开的数据 类型,其中包 含 一个系统分 配的 属性 对象。函 数pthread_mutex_init 用来生成一个互 斥锁。NULL 参数表明 使用默认 属性。如果 需要声明特 定属性 的互 斥锁,须 调用 函数 pthread_mutexattr_init。函数 pthread_mutexattr_setpshared 和函数 pthread_mutexattr_settype 用来设置互 斥锁 属性。前一个 函数设置 属性 pshared,它有 两个PDF 文件使用 pdfFactory Pro 试用版本创建 取值,PTHREAD_PROCESS_PRIV ATE 和 PTHREAD_PROCESS_SHARED。前者用来不同进程中的线程同步,后者 用于同 步本进程的 不同线程。在 上面的例子 中,我 们使用的是 默认属 性PTHREAD_PROCESS_ PRIVATE。后 者 用 来 设 置 互 斥 锁 类 型,可 选 的 类 型 有PTHREAD_MUTEX_NORMAL、PTHREAD_MUTEX_ERRORCHECK、PTHREAD_MUTEX_RECURSIVE和 PTHREAD _MUTEX_DEFAULT。它们分 别定义 了不 同的上 锁、解锁机制,一 般情况 下,选用最后一个 默认 属性。锁定一个互 斥 量使用函数 pthread_mutex_lock(),它 尝试 锁定一个互 斥 量,如果该 互 斥量已经 被其 它线程 锁定,该函数把调用自己的线程挂起,一旦该互斥量解 锁,它将恢复 运行并锁 定该互 斥量。这个线程在做 完它的 事情后必须 释 放这个互 斥 量,解除 锁 定使 用函数pthread_mutex_unlock()。用完一个互 斥 量后必须 销毁 它,这时 没有 任何 线程 再需 要它了,最后 一个 使用该互 斥量的线程 必须 销毁 它,销毁互斥量 使用函数 pthread_mutex_destroy():rc=pthread_mutex_destroy(&mutex);这个调用 之后,mutex 不能 再作为一个互 斥量,除非 我们再初始化 一 次,如果 在销毁 互斥量 后,仍然有线程 试图锁 定或者 解锁它,那么将 会从 锁定或 解锁函数得到 一个EINVAL错误 代码。当一个互 斥量 已经 被别 的线程 锁定后,另一个线程调用pthread_mutex_lock()函数去锁定它时,会挂起 自己的线程 等待 这个互 斥量被解锁。可能 存在这 样一种情 形,这个互 斥量一直没 有被解锁,等待 锁 定它的线程 将一 直被挂着,这时 我 们称这个线程处于饥饿 状态,即 它请求 某个资源,但永远 得不到它。用户 必须 在程序中 努力 避免 这种“饥饿”状态 出现,pthread函数 库不 会自 动处理这 种情 形。但是 pthread函 数库可 以确定 另外 一种状态,即“死锁”。一组线程中的 所有线程 都在等待 被同组中 另外 一些线程 占用的资源,这时,所 有线程 都因 等待互斥 量而披挂起,它们中 任何一个 都不能 恢复 运行,程序 无法 继续 运行下 去这时 就产生了死锁。pthread库可 以跟踪 这种情 形最后一个线程 试图调用 pthread_mutex_lock()时会 失败,并返回 类型为 EDEADLK的错误。用户 必须 检查 这种错误,并 解决 死锁问题。8.2.2 条件变量在 8.1.1 节中我们讲述 了如 何使用互 斥锁 来实现 线程间数据的共享和通信,互斥锁 一个明显 的缺点是它 只 有两种状态:锁定 和非锁定。在某些 情况 下,例如:在 图形 用户 界面程序中,一个线程 读取 用户 输入,另一个线程处理 图形 输出。第三 个线程 发送请求 到服务 器并 处理其 响应。当服务 器的 响应到达时处理 服务 器的线程 必须 可以通 知画图形 的线程,画图形的线程 把相应的结 果显示给用户。管理用户 输入的线程 必须 总是能响 应用户,例如,允许 用户取 消正在由处理 服务 器的线程 执 行的耗时的 操作。这 表明 线程间 必须 可以相互 传 递信息。这时 候需 要引入 条 件变量。条件变量是一 种可以使线程(不消耗 CPU)等待 某 些事件发生 的机制。某些线程 可能 守 候着一个 条件变量,直到 某个其它的线程 给这个 条件变量 发送一个信号(即发送一个通 告),这PDF 文件使用 pdfFactory Pro 试用版本创建 时这些线程中的一个线程就会苏醒,处理这个 事件。也有 可能 利用对条件变量的 广播 唤醒 所有守 候着这个 条件变量的线程。但条件变量 不提供锁 定,所以它 必须 与一个互 斥量同时 使用,提供 访问这个 环境 变量时 必要 的锁 定。条件变量通 过允许 线程 阻塞 和等待另 一个线程 发送信号的 方法 弥补 了互斥锁 的 不足,它常和互 斥锁 一起使 用。使用时,条件变量 被用来阻塞 一个线程,当 条件不满足 时,线程 往往解开相 应的互 斥锁 并等待 条件发生 变化。一旦其它的 某 个线程 改变了条件变量,它将通知 相应的 条件变量 唤醒 一个 或多个正被此 条件变量 阻塞 的线程。这些线程 将重 新锁定互斥锁 并 重新测 试条件是 否满足。一 般说来,条件变量 被用来 进行线程间的同 步。下面通过一个 例子来介绍 一下条件变量:pthread_mutex_t count_mutex;pthread_cond_t count_nonzero;unsigned int count;decrement_count()pthread_mutex_lock(&count_mutex);while(count=0)pthread_cond_wait(&count_nonzero,&count_mutex);count=count-1;pthread_mutex_unlock(&count_mutex);increment_count()pthread_mutex_lock(&count_mutex);if(count=0)pthread_cond_signal(&count_nonzero);count=count+1;pthread_mutex_unlock(&count_mutex);条 件 变 量 的 结 构 为pthread_cond_t,创 建 条 件 变 量 时 必 须 首 先 声 明 一 个 类 型 为pthread_cond_t 的变量,然后 对它进 行初始化。初始化 可以 如下所示:pthread_cond_t cond=PTHREAD_COND_INITIALIZER;但是,由于 PTHREAD_COND_INITIALIZER是一个 结构,所以只能 在条件变量 声明 时对它进 行初始化,在 运行时对条件变量进 行初始化 只能 使用 pthread_cond_init()函 数。int pthread_cond_init(pthread_cond_t*cond,pthread_condattr_t*cond_attr);cond是 一 个 指 向 结 构pthread_cond_t的 指 针,cond_attr是 一 个 指 向 结 构pthread_condattr_t 的指 针。结构pthread_condattr_t 是条 件变量的 属性结构,和互 斥锁 一 样我 们 可 以用它 来 设置 条 件变量是进程内可 用 还 是进程间可 用,默认值 是PTHREAD_ PROCESS_PRIVATE,即此条件变量 被同一进程内的 各 个线程 使用。函 数pthread_cond_wait()使 线 程 阻 塞 在 一 个 条 件 变 量 上,解 锁 可 以 使 用PDF 文件使用 pdfFactory Pro 试用版本创建 pthread_cond_signal()(只 唤 醒 守 候 着 这 个 条 件 变 量 的 一 个 线 程)或 者 使 用pthread_cond_broadcast()函数(唤醒 守候 着这个 条件变量的 所有线程)。如上例 所示:int rc=pthread_cond_signal(&count_nonzero);或者使 用广播 函数:int rc=pthread_cond_broadcast(&count_nonzero);rc 在成 功时返回 0,失败 时返回 一个 非 0 值,反映 发生错误 的类型(EINVAL 说明函数参数 不是条件变量,ENOMEM 说明系统 没有可用的内存)。注意:发 送信号成 功不 表明 一定有线程 被唤醒,可能 这时 候没 有线程在 守护 该 条件变量,并且 这个信号会 丢 失,不会被使用,如果 有新的线程开 始 守护 该条件变量,那么必须要 有 新的信号 才能 唤醒 它。线程 可以通 过两 个函数pthread_cond_wait()和 pthread_cond_timedwait()来 守候条件变量,这 两个函数以一个 条件变量和一个互斥量(应该 在调用 之前锁定)为参数,解除 对互斥 量的锁 定,挂起 线程的 执行,并处于 等待状态,直到 条件变量 接收到 信号。如果该 线程 被条 件变量 唤醒,守候函 数再次自动锁定 互斥量,并开始执 行。这两 个函数的 唯一 区别 是:pthread_cond_timedwait()允许 用户 给定 一个时间间 隔,过了 这个间 隔,函 数总是返回,返回 值为 ETIMEDOUT,表 示在时间间 隔 之内条件变量 没接到 信号,阻塞 也 被解除。而如果没 有信号 pthread_cond_wait()将无限期 等待 下去。8.2.3 信号量如果 我们编写 的程序中 使用了多 线程,那么在多用户 多进程系统中,需要保证 只有一个线程 能够对某 些资源(临界 资源)进行排 他性访问(这些资源 叫做临界 资源),为 防止多个程序访问 一个资源 引发 的问题,我们需要有一 种方法生 成并 使用一个 记号,使 得任意 时刻只有一个线程 拥有对该 项 资源的 访问权。对此 Dijkstra 提出了”信号量”概念。信号量是一 种特 殊的变量,它 只能 取正 整数值,对这些 正整数只能 采 取两种操 作:P操作(代表 等待,关操 作)和 V 操 作(代表 信号,开操作)。P/V 操作的 定义 如下(假设我们有一个信号量sem):P(sem):如果 sem 的值大于 0,则 sem减一;如果 sem 的值为 0,则挂起 该线程。V(sem):如果 有其它进程 因等待 sem 而被 挂起,则 让它恢复 执行,如果没 有线程 等待sem而被 挂起,则 sem加上 1。n信号量 集 的创建与打开要使 用信号量,首先必须 创建一个信号量。创建信号量的信号如下:#include#include#include int semget(key_t key,int nsems,int flag);函数 semget()用于创建一个新的信号量 集或打开 个己存在的信号量集。其 中,参数 keyPDF 文件使用 pdfFactory Pro 试用版本创建 表示 所创建 或打开的信号量集的键。参 数 nsems表示创建的信号量集中信号量的个数,此参数只 在创建一个 新 的信号量 集时有 效。参数 f1ag 表示调用 函数的 操作类 型,也 可用于设置信号量 集的访问权 限,两者通过逻辑 或表示,它低端 的九个位 是该信号量的 权限,可以与 键值 IPC_CREATE 作按位或操作以创建一个新的信号量,即使 在设置 了 IPC_CREATE 后给 出的是一个 现有信号量的 键字,也并不 是一个 错误。如果 IPC_CREATE 标识 在函数 里用不着,函数 就会忽略 它的作用。我们可以 使用 IPC_CREATE 和 IPC_EXCL 标识来 创建 出一个独一无二 的新的信号量 来,如果该 信号量 已经 存在,则返回 一个 错误。调用 函数 semget()的作用由参 数 key 和 flag 决 定,此函数调用成 功时,返回 值为信号量的 引用标识符;调用 失败 时,返回 值为-1。n对信号量的 操作对信号量的 操 作使用如下函 数:#include#include#include int semop(int semid,struct sembuf semoparray,size_t nops);参数 semid 是信号量 集的引用 id,semoparray是一个 sembuf 类型数组,sembuf 结构 用于指 定调用 semop()函数所 做的操作,数组semoparray中元素 的个数由nops 决定。sembuf的结构 如下:struct sembuf ushort sem_num;short sem_op;short sem_flag;其中,sem_num 指定要 操作的信号量。sem_op用于 表示所执行的操 作。相 应取值和 含义见 下。sem_flag 为 操作标记。与 此函数相 关的有 IPC_NOWAIT 和 SEM_UNDO。1、sem_op0:表示线程 对资源 使用完 毕,交回该资源。此时信号量 集的 semid_ds结构的 sem_base.semval将加 上 sem_op的值。如果此 时设置 了 SEM_UNDO 位,则信号量的调整值将 减去 sem_op的绝对值。2、sem_op=0:表示进程 要等待,直到 sem_base.semval的值变为 0。3、sem_op0:表示表示进程 希望 使用资源。此 时将比较sem_base.semval 和 sem_op的绝对值的大 小。如果 sem_base.semval大于 等于 sem_op 的绝对值,表示资源 足够分配 给该进程,则 sem_base.semval 将减 去 sem_op 的 绝对 值。如果此 时设置 了SEM_UNDO 位,则信号量的调 整值将 加上 sem_op的绝对值。如果 sem_base.semval小于 sem_op的绝对值,表示资源 不足。如果 设置 了 IPC_NOWAIT 位,则函数

    注意事项

    本文(Linux多线程编程-.pdf)为本站会员(索****)主动上传,淘文阁 - 分享文档赚钱的网站仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知淘文阁 - 分享文档赚钱的网站(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    关于淘文阁 - 版权申诉 - 用户使用规则 - 积分规则 - 联系我们

    本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

    工信部备案号:黑ICP备15003705号 © 2020-2023 www.taowenge.com 淘文阁 

    收起
    展开