ImageVerifierCode 换一换
格式:DOC , 页数:64 ,大小:500.50KB ,
资源ID:1280972      下载积分:30 文钱
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,省得不是一点点
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.wenke99.com/d-1280972.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: QQ登录   微博登录 

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(linux多线程编程.doc)为本站会员(滴答)主动上传,文客久久仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知文客久久(发送邮件至hr@wenke99.com或直接QQ联系客服),我们立即给予删除!

linux多线程编程.doc

1、 第一章 线程基础知识 . 2 一什么是线程 . 2 二线程的优点 . 2 三线程的缺点 . 2 四线程的结构 . 2 五线程标识 . 2 六线程的创建 . 3 七 .线程的终止 . 4 八、一次性初始化 . 7 九、线程的私有数据 . 9 第二章 线程高级知识 . 10 一线程属性 . 10 二、线程的分离状态 .11 三、线程的继承性 . 12 四、线程的调度策略 . 13 五、线程的调度参数 . 13 六、线程的作用域 . 16 七、线程堆栈的大小 . 16 八、线程堆栈的地址 . 17 九、线程栈末尾的警戒缓冲区大小 . 17 第三章 Posix 有名信号灯 . 18 一、 posix

2、 有名信号灯函数 . 18 二、关于 posix 有名信号灯使用的几点注意 . 23 三、 posix 有名信号灯应用于多线程 . 24 四、 posix 有名信号灯应用于多进程 . 25 五、基于内存的信号灯 . 28 第四章 互斥量 . 38 一、什么是互斥锁 . 38 二、初始化 /回收互斥锁 . 38 三、对互斥量加减锁 . 39 四、互斥锁属性 . 44 五、应用互斥量需要注意的几点 . 46 第五章 条件变量 . 46 一、什么是条件变量 . 46 二、条件变量函数 . 47 三、条件变量属性 . 52 四、条件变量与互斥锁、信号量的区别 . 53 第六章 共享内存 . 53 一、

3、什么是共享内存区 . 54 二、 mmap . 54 三、 posix 共享内存函数 . 58 四、 ftruncate 和 fstat 函数 . 59 五、共享内存区的写入和读出 . 61 六、程序例子 . 62 第一章 线程基础知识 一什么是线程 在一个程序里的多个执行路线就叫做线程。更准确的定义是:线程是“一个进程内部的一个控制序列”。 典型的 unix 进程可以看成只有一个控制线程:一个进程在同一时刻只做一件事情。有了多个控制线程以后,在 程序设计时可以把进程设计成在同一时刻能够做不止一件事,每个线程处理各只独立的任务。 二线程的优点 ( 1) 通过为每种事件类型的处理分配单独的线程,

4、能够简化处理异步时间的代码。 ( 2) 多个线程可以自动共享相同的存储地址空间和文件描述符。 ( 3) 有些问题可以通过将其分解从而改善整个程序的吞吐量。 ( 4) 交互的程序可以通过使用多线程实现相应时间的改善,多线程可以把程序中处理用户输入输出的部分与其它部分分开。 三线程的缺点 线程也有不足 之处。编写多线程程序需要更全面更深入的思考。在一个多线程程序里,因时间分配上的细微偏差或者因共享了不该共享的变量而造成不良影响的可能性是很大的。调试一个多线程程序也比调试一个单线程程序困难得多。 四线程的结构 线程包含了表示进程内执行环境必需的信息,其中包括进程中标识线程的线程 ID,一组寄存器值、

5、栈、调度优先级和策略、信号屏蔽子, errno 变量以及线程私有数据。进程的所有信息对该进程的所有线程都是共享的,包括可执行的程序文本,程序的全局内存和堆内存、栈以及文件描述符。 五线程标识 就像每个进程有一个进程 ID 一样,每个线程也有一个线程 ID,进程 ID 在整个系统中是唯一的,但线程不同,线程 ID 只在它所属的进程环境中有效。线程 ID 用 pthread_t 数据类型来表示,实现的时候可以用一个结构来代表 pthread_t数据类型,所以可以移植的操作系统不能把它作为整数处理。因此必须使用函数来对来对两个线程 ID 进行比较。 1 名称 :: pthread_equal 功能:

6、 比较两个线程 ID 头文件: #include 函数原形: int pthread_equal(pthread_t tid1,pthread_t tid2); 参数: tid1 进程 1id tid2 进程 2id 2 六线程的创建 3 当 pthread_creat 成功返回时, tidp 指向的内存单元被设置为新创 建线程的线程ID。 attr 参数用于定制各种不同的线程属性。可以把它设置为 NULL,创建默认的线程属性。 新创建的线程从 start_rtn 函数的地址开始运行,该函数只有一个无类型指针参数 arg,如果需要向 start_rtn 函数传递的参数不止一个,那么需要把这些参

7、数放到一个结构中,然后把这个结构的地址作为 arg 参数传入。 #include void printids(const char *s) printf(“%s pid:%u tid:%u n“, s,getpid(),pthread_self(); void *thr_fn(void *arg) printids(“new thread: “); 返回值: 若相等返回非 0 值,否则返回 0 名称 :: pthread_self 功能: 获取自身线程的 id 头文件: #include 函数原形: pthread_t pthread_self(void); 参数: 无 返回值: 调用线程的线

8、程 id 名称 :: pthread_create 功能: 创建线程 头文件: #include 函数原形: int pthread_create(pthread_t *restrict tidp,const pthread _attr_t *restrict attr,void *(*start_rtn)(void),void *restrict arg); 参数: 返回值: 若成功返回则返回 0,否则返回错误编号 int main() int err; pthread_t tid; err=pthread_create( if(err=0) printf(“cant create thre

9、ad:%sn”,strerror(err); printids(“main thread: “); sleep(1); exit(0); 关于进程的编译我们都要加上参数 lpthread 否则提示找不到函数的错误。 具体编译方法是 cc lpthread o gettid gettid.c 运行结果为 main thread: pid 14954 tid 134529024 new thread: pid 14954 tid 134530048 七 .线程的终止 线程是依进程而存在的,当进程终止时,线程也就终止了。当然也有在不终止整个进程的情况下停止它的控制流。 ( 1)线程只是从启动例程中返

10、回,返回值是线 程的退出码。 ( 2)县城可以被同一进程中的其他线程取消。 ( 3)线程调用 pthread_exit. 4 rval_prt 是一个无类型指针,与传给启动例程的单个参数类似。进程中的其他线程可以调用 pthread_join 函数访问到这个指针。 5 名称 :: pthread_exit 功能: 终止一个线程 头文件: #include 函数原形: void pthread_exit(void *rval_ptr); 参数: 返回值: 无 名称 :: pthread_join 功能: 获得进程的终止状态 头文件: #include 函数原形: int pthread_join

11、(pthread_t thread,void *rval_ptr); 参数: 返回值: 若成功返回 0,否则返回错误编号。 当一个线程通过调用 pthread_exit 退出或者简单地从启动历程中返回时,进程中的其他线程可以通过调用 pthread_join 函数获得进程的退出状态。调用pthread_join 进程将一直 阻塞,直到指定的线程调用 pthread_exit,从启动例程中或者被取消。 如果线程只是从它的启动历程返回, rval_ptr 将包含返回码。 #include #include void *thr_fn1(void *arg) printf(“thread 1 retu

12、rningn”); return(void *)1); void *thr_fn2(void *arg) printf(“thread 2 exitingn”); return(void *)2); int main() pthread_t tid1,tid2; void *tret; pthread_create( pthread_create( pthread_join(tid1, printf(“thread 1 exit code %dn”,(int)tret); pthread_join(tid2, printf(“thread 2 exit code %dn”,(int)tret)

13、; exit(0); 运行结果是: thread 1 returning thread 2 exiting thread 1 exit code 1 thread 2 exit code 2 6 名称 :: pthread_detach 功能: 使线程进入分离状态。 在默认情况下,线程的终止状态会保存到对该线程调用 pthread_join,如果线程已经处于分离状态,线程的底层存储资源可以在线程终止时立即被收回。当线程被分离时,并不能用 pthread_join 函数等待它的终止状态。对分离状态的线程进行pthread_join 的调用会产生失败,返回 EINVAL.pthread_detac

14、h 调用可以用于使线程进入分离状态。 7 在默认的情况下, pthread_cancel函数会使由 tid 标识的线程的行为表现为如同调用了参数为 PTHEAD_CANCELED 的 pthread_exit 函数,但是,线程可以选择忽略取消方式和控制取消方式。 pthread_cancel并不等待线程终止,它仅仅提出请求。 8 线程可以安排它退出时需要调用的函数,这样的函数称为线程清理处理程序,线程可以建立多个清理处理程序。处理程序记录在栈中,也就是说它们的执行顺序与它们注 册时的顺序相反。 要注意的是如果线程是通过从他的启动例程中返回而终止的,它的处理程序就不会调用。还要注意清理处理程序是

15、按照与它们安装时相反的顺序调用的。 #include 头文件: #include 函数原形: int pthread_detach(pthread_t tid); 参数: 返回值: 若成功则返回 0,否则返回错误编号。 名称 :: pthread_cancel 功能: 取消同一进程中的其他线程 头文件: #include 函数原形: int pthread_cancel(pthread_t tid); 参数: tid 线程 id 返回值: 若成功返回 0,否则返回错误编号。 名称 :: pthread_cancel_push/ pthread_cancel_push_pop 功能: 线程清理处

16、理程序 头文件: #include 函数原形: void pthread_cancel_push(void (*rtn)(void *), void *arg); void pthread_cancel_pop(int execute); 参数: rtn 处理程序入口地址 arg 传递给处理函数的参数 返回值: 无 #include void cleanup(void *arg) printf(“cleanup: %sn”,(char *)arg); void *thr_fn(void *arg) /*线程入口地址 */ printf(“thread startn”); pthread_cle

17、anup_push(cleanup,”thread first handler”);/*设置第一个线程处理程序 */ pthread_cleanup_push(cleanup,”thread second handler”); /*设置第二个线程处理程序 */ printf(“thread push completen”); pthread_cleanup_pop(0); /*取消第一个线程处理程序 */ pthread_cleanup_pop(0); /*取消第二个 线程处理程序 */ int main() pthread_t tid; void *tret; pthread_creat(

18、/*创建一个线程 */ pthread_join(tid, /*获得线程终止状态 */ ptinrf(“thread exit code %dn”,(int)tret); 八、一次性初始化 有时候我们需要对一些 posix 变量只进行一次初始化,如线程键(我下面会讲到)。如果我们进行 多次初始化程序就会出现错误。 在传统的顺序编程中,一次性初始化经常通过使用布尔变量来管理。控制变量被静态初始化为 0,而任何依赖于初始化的代码都能测试该变量。如果变量值仍然为 0,则它能实行初始化,然后将变量置为 1。以后检查的代码将跳过初始化。 但是在多线程程序设计中,事情就变的复杂的多。如果多个线程并发地执行

19、初始化序列代码, 2 个线程可能发现控制变量为 0,并且都实行初始化 ,而该过程本该仅仅执行一次。初始化的状态必须由互斥量保护。 如果我们需要对一个 posix 变量静态的初 始化,可使用的方法是用一个互斥量对该变量的初始话进行控制。但有时候我们需要对该变量进行动态初始化,pthread_once 就会方便的多。 9. 类型为 pthread_once_t 的变量是一个控制变量。控制变量必须使用PTHREAD_ONCE_INIT 宏静态地初始化。 pthread_once 函数首先检查控制变量,判断是否已经完成初始化,如果完成就简单地返回;否则, pthread_once 调用初始化函数,并且

20、记录下初始化被完成。如果在一个线程初始时,另 外的线程调用 pthread_once,则调用线程等待,直到那个现成完成初始话返回。 下面就是该函数的程序例子: #include pthread_once_t once=PTHREAD_ONCE_INIT; pthread_mutex_t mutex; /*互斥量,我们后面会讲到 */ void once_init_routine(void) /*一次初始化函数 */ int status; status=pthread_mutex_init(/*初始化 互斥量 */ if(status=0) printf(“Init success!,My i

21、d is %u”,pthread_self(); void *child_thread(void *arg) printf(“Im child ,My id is %u”,pthread_self(); pthread_once( /*子线程调用一次性初始化函数 */ int main(int argc,char *argv ) pthread_t child_thread_id; pthread_create(/*创建子线程 */ printf(“Im father,my id is %u”,pthread_self(); pthread_once(/*父线程调用一次性初始化函数 */ 名称

22、 : pthread_once 功能: 一次性初始化 头文件: #include 函数原形: pthread_once_t once_control=PTHREAD_ONCE_INIT; int pthread_once(pthread_once_t *once_control,void(*init_routine)(void); 参数: once_control 控制变量 init_routine 初始化函数 返回值: 若成功返回 0,若失败返回错误编号。 pthread_join(child_thread_id,NULL); 程序运行结果如下: ./once Im father,My id

23、 is 3086874304 Init success!,My id is 3086874304 Im child, My id is 3086871472 从上面的结果可以看到当主函数初始化成功后,子函数初始化失败。 九、线程的私有数据 在进程内的所有线程共享相同的地址空间,任何声明为静态或外部的变量,或在进程堆声明的变量,都可以被进程所有的线程读写。那怎样才能使线程序拥有自己的私有数据呢。 posix 提供了一种方法,创建线程键。 10. 第一个参数为指向一个键值的指针,第二个参 数指明了一个 destructor函数(清理函数),如果这个参数不为空,那么当每个线程结束时,系统将调用这个函

24、数来释放绑定在这个键上的内存块。这个函数常和函数 pthread_once 一起使用,为了让这个键只被创建一次。函数 pthread_once 声明一个初始化函数,第一次调用 pthread_once 时它执行这个函数,以后的调用将被它忽略。 下面是程序例子: #include pthread_key_t tsd_key; pthread_once_t key_once=PTHREAD_ONCE_INIT; void once_routine(void) int status; status=pthread_key_create(/*初始化线程私有数据键 */ if(status=0) pri

25、ntf(“Key create success! My id is %un”,pthread_self(); 名称 :: pthread_key_create 功能: 建立线程私有数据键 头文件: #include 函数原形: int pthread_key_create(pthread_key_t *key,void(*destructor)(void *); 参数: key 私有数据键 destructor 清理函数 返回值: 若成功返回 0,若失败返回错误编号。 void *child_thread(void *arg) printf(“Im child,My id is %un”,pt

26、hread_self(); pthread_once(/* 调用一次性初始化函数 */ int main(int argc,char *argv ) pthread_t child_thread_id; pthread_create( printf(“Im father,my id is%un”,pthread_self(); pthread_once( 程序运行结果如下: Im father,My id is 3086231232 Key create success! My id is 3086231232 Im child,My id is 2086228400 第二章 线程 高级知识

27、一线程属性 线程具有属性,用 pthread_attr_t 表示,在对该结构进行处理之前必须进行初始化,在使用后需要对其去除初始化。我们用 pthread_attr_init 函数对其初始化,用 pthread_attr_destroy 对其去除初始化。 1 调用 pthread_attr_init 之后, pthread_t 结构所包含的内容就是操作系统实现支持的线程所有属性的默认值。 如果要去除对 pthread_attr_t 结构的初始化,可以调用 pthread_attr_destroy 函数。如果 pthread_attr_init 实现时为属性对象分配了动态内存空间,pthread

28、_attr_destroy 还会用无效的值初始化属性对象,因此如果经pthread_attr_destroy去除初始化之后的 pthread_attr_t结构被 pthread_create 函数调用,将会导致其返回错误。 名称 :: pthread_attr_init/pthread_attr_destroy 功能: 对线程属性初始化 /去除初始化 头文件: #include 函数原形: int pthread_attr_init(pthread_attr_t *attr); int pthread_attr_destroy(pthread_attr_t *attr); 参数: Attr 线程属性变量 返回值: 若成功返回 0,若失败返回 -1。

Copyright © 2018-2021 Wenke99.com All rights reserved

工信部备案号浙ICP备20026746号-2  

公安局备案号:浙公网安备33038302330469号

本站为C2C交文档易平台,即用户上传的文档直接卖给下载用户,本站只是网络服务中间平台,所有原创文档下载所得归上传人所有,若您发现上传作品侵犯了您的权利,请立刻联系网站客服并提供证据,平台将在3个工作日内予以改正。