线程与进程一样,具有创建、退出、取消和等待等基本操作,可以独立完成特定事物的处理;线程同样有自己的特有属性,如线程也有唯一标识自己的线程ID,但线程占用更少的资源
什么是线程?线程的定义
“轻量级进程”
简单来说线程就是进程中的一个执行流,更准确来说:线程是“一个进程内部的控制序列”
- 进程是资源竞争的基本单位
- 线程是程序执行的最小单位
创建线程
int pthread_create(pthread_t *newthread,
const pthread_attr_t *attr, //NULL
void*(*start_routine)(void*),//线程要执行的函数
void *arg);
//newthread:线程ID
//attr:设置线程的属性,主要设置与栈相关的属性,一般情况下设置为NULL,使用系统默认属性
//start_routine:线程运行的代码起始地址,就是要运行的那个函数
//arg:运行函数的参数地址。如果需要传入多个参数,则需要使用一个包含这些参数的结构体地址
返回:成功返回0,失败返回非0
线程的退出
//线程退出,终止
void pthread_exit(void *retval);
注意:pthread_exit()返回的指针所指向的内存空间必须是全局的或者malloc分配的,不能在线程的栈上分配,因为当其它线程得到这个返回的指针时,线程函数已经退出了
线程等待
当主线程等待子线程的结束,显示的等待某线程的结束可以调用pthread_join()函数,其类似于进程的wait()函数。
int pthread_join(pthread_t thread,viod **thread_return);
//thread:被等待的线程id
//thread_return:用户自定义的指针,
//指向一个保存等待线程的完整退出状态的静态区域,它可以用来存储被等待线程的返回值
此函数将调用该函数的线程挂起,直到所等待id为thread的线程退出。
然而,被等待的(thread)线程会有不同的方法终止,通过pthread_join得到的终止状态也是不同的:
- 如果thread线程通过 return返回 ,value_ptr所指向的单元⾥里存放的是thread线程函数的返回值。
- 如果thread线程被别的线程调⽤ pthread_cancel异常终止 ,value_ptr所指向的单元⾥里存放的是常数PTHREAD_CANCELED。
- 如果thread线程是⾃己调⽤用 pthread_exit终⽌ 的,value_ptr所指向的单元存放的是传给pthread_exit的参数。
- 如果对thread线程的终止状态不感兴趣,可以传NULL给 value_ptr 参数。
取消线程
1、发起取消操作
取消线程是指取消一个正在执行线程的操作。一个线程能够被取消并终止执行需要满足以下条件:
- 线程是否可以被其它取消,默认可以被取消
- 线程处于可取消的点才能被取消。也就是说。即使该线程被设置为可取消,另一个线程发起取消操作,该线程也不是一定马上终止,只有在可取消点才能终止执行
函数pthread_cancel()用来向某线程发送取消操作
int pthread_cancel(pthread_t thread);
//thread:线程id
返回:成功返回0,失败返回错误码
只有当目标线程的可取消状态为PTHREAD_CANCEL_ENABLE时,才能取消。
2、设置可取消状态(可以/不可以)
int pthread_setcancelstate(int _state,int* _oldstate);
//state:要设置的新状态
//oldstate:存储原来的状态
两种状态:
- PTHREAD_CANCEL_DISABLE
- PTHREAD_CANCEL_ENABLE
3、设置取消类型(立即/取消点)
pthread_sercanceltype()函数用来设置取消类型,即允许被取消的线程在接收到取消操作后是立即终止还是在取消点终止
int pthread_setcanceltype(int _type,int* _oldtype)
type的两种类型:
- PTHREAD_CANCEL_ASYNCHRONOUS,立即取消
- PTHREAD_CANCEL_DEFERRED,到取消点取消
下面是一个取消线程的例子,主线程使用pthread_cancel函数来取消线程。
由于子线程调用pthread_setcancelstate函数设置了线程的取消状态为PYHREAD_CANCEL_DISABLE,所以此时的子线程不能被取消,主线程处于等待状态。经过一段时间,子线程有调用pthread_setcancelstate函数,将子进程的取消状态改为PYHREAD_CANCEL_ENABLE,此时子线程可以被取消,从而使主线程能够取消子线程。代码如下: