第十一章:线程

11.1:引言

本章介绍多线程的使用

11.2:线程概念

典型的Unix进程可以看作只有一个控制线程:一个进程在同一时刻只做一件事情。

11.3:线程标识

每个线程跟进程一样,都有一个线程ID来标识。

#include <pthread.h>
int pthread_equal(pthread_t tid1, pthread_t tid2); // 判断两个线程ID是否相等,若相等,返回非0,否则返回0
pthread_t pthread_self(void); // 返回调用线程的线程ID

11.4:线程创建

默认一个进程只包含有个线程,如果要实现多线程,首先得创建新的线程,可以使用函数pthread_create来实现。

#include <pthread.h>
// 若成功返回0,否则返回错误编号
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void*(*start_rtn)(void), void *restrict arg);

如果成功,tidp指向的内存保存线程ID,attr是线程属性,可以为NULL,start_rtn是线程函数,arg是传递给线程函数的参数。

实例:11.1 测试线程ID

 

11.5:线程终止

如果进程中任一线程调用了exit、_exit、_Exit,那么整个进程就会终止。与此类似,如果信号的默认动作是终止进程,那么信号发送到线程会终止整个进程。

单个线程可以通过下列三种方式退出,在不终止整个进程的情况下停止它的控制流:

1.线程只是从启动例程中返回,返回值是线程的退出码。

2.线程可以被同一个进程中的其他线程取消。

3.线程调用pthread_exit()。

#include <pthread.h>
void pthread_exit(void *rval_ptr);

rval_ptr是一个无类型指针,与传给启动例程的单个参数类似。进程中的其他线程可以调用pthread_join来访问这个指针。

#include <pthread.h>
int pthread_join(pthread_t thread, void **rval_ptr); // 若成功返回0,否则返回错误编号

调用线程将一直阻塞,直到指定的线程调用pthread_exit()、从启动例程返回或被取消。

实例:11-2 获得线程退出状态

实例:11-3 pthread_exit参数的不正确使用

线程可以通过调用pthread_cancel函数来请求取消同一进程中的其他进程。

#include <pthread.h>
int pthread_cancel(pthread_t tid); // 若成功则返回0,否则返回错误编号

注意:pthread_cancel并不等待线程终止,它仅仅提出请求。

线程可以安排它退出时需要调用的函数,这与进程可以用atexit函数安排进程退出时需要调用的函数是类似的。这样的函数称为线程清理处理程序(thread cleanup handler)。线程可以建立多个清理处理程序。处理程序记录在栈中,也就是说它们的执行顺序与它们注册时顺序相反。

#include <pthread.h>
void pthread_cleanup_push(void (*rtn)(void*), void *arg);
void pthread_cleanup_pop(int execute);

当线程执行以下动作时调用清理函数,调用参数为arg,清理函数rtn的调用顺序是由pthread_cleanup_push函数来安排的。

1.调用pthread_exit时。

2.相应取消请求时。

3.用非零execute参数调用pthread_cleanup_pop时。

如果execute参数置为0,清理函数将不被调用。无论哪种情况,pthread_cleanup_pop都将删除上次pthread_cleanup_push调用建立的清理处理程序。

实例:11-4 线程清理处理程序

默认情况下,线程的终止状态会保存到对该线程调用pthread_join,如果线程已经处于分离状态,线程的底层存储资源可以在线程终止时被立即回收。当线程分离时,并不能用pthread_join函数等待它的终止状态。对分离状态的线程进行pthread_join的调用会产生失败,返回EINVAL。pthread_detach调用可以用于使线程进入分离状态。

#include <pthread.h>
int pthread_detach(pthread_t tid);

分离状态--即该线程在终止时就可以回收其资源。

11.6:线程同步

1.互斥量

2.避免死锁

3.读写锁

4.条件变量

11.7:小结

在本章中介绍了线程的概念,讨论了现有的创建线程和销毁线程的POSIX原语;此外,还介绍了线程同步的问题,讨论了三种基本的同步机制:互斥、读写锁以及条件变量,了解如何使用它们来保护共享资源。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。