线程控制相关函数
POSIX线程库(用户级库)
- 线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以“pthread_”打头的
- 要使用这些函数库,要通过引入头文 <pthread.h>
- 链接这些线程函数库时要使用编译器命令的 “-lpthread” 选项
1、创建线程(pthread_create)
函数使用
功能:创建一个新的线程
原型int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine), (void*), void *arg);
参数:
thread: 返回创建出新线程的ID
attr: 设置线程的属性,attr为NULL表示使用默认属性(一般设置为NULL)
start_routine: 是个函数地址,线程启动后要执行的函数
arg: 传给线程启动函数的参数
返回值: 成功返回0;失败返回对应的错误码
错误检查:
- 传统的一些函数是成功返回0,失败返回-1,并且对全局变量errno赋值以指示错误。
- pthreads函数出错时不会设置全局变量errno(而大部分其他POSIX函数会这样做)。而是将错误代码通过返回值返回
- pthreads同样也提供了线程内的errno变量,以支持其它使用errno的代码。对于pthreads函数的错误,建议通过返回值业判定,因为读取返回值要比读取线程内的errno变量的开销更小。
示例代码
输出结果和分析如下:
2、线程终止(三种方法)
如果需要只终⽌某个线程⽽不终⽌整个进程,可以有三种⽅法:
- 从线程函数内部return。 这种⽅法对主线程不适⽤,从main函数return相当于调⽤exit。也就是说我想要终止这个线程就在这个线程内部进行return,如果在主线程内部return则意味着进程退出。
- 新线程可以调⽤pthread_ exit终⽌⾃⼰,pthread_ exit的参数就是最后该线程的返回值,是一个输出型参数。但是新线程不能调exit,主线程则可以调用exit,主线程调用exit说明进程退出,相当于return了,因为主线程可以等待所有新线程退出了它才退出。
函数使用场景:
- ⼀个线程可以调⽤pthread_ cancel终⽌同⼀进程中的另⼀个线程(一个线程可以被取消)
函数使用场景:
pthread_exit函数使用
功能: 线程终⽌
原型void pthread_exit(void *value_ptr);
参数
value_ptr: value_ptr不要指向⼀个局部变量。
返回值: ⽆返回值,跟进程⼀样,线程结束的时候⽆法返回到它的调⽤者(⾃⾝)
这里的value_ptr参数的类型时void*,我们发现这里pthread_exit的参数和线程的返回值的类型一样,可以理解为,线程退出时如果调用pthread_exit函数来退出该线程,那么就是通过该函数的参数将返回值带出的,也就是圆括号里的参数就是该线程的返回值。
需要注意,pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是⽤malloc分配的,不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了。
pthread_cancel函数使用
功能: 取消⼀个执⾏中的线程
原型int pthread_cancel(pthread_t thread);
参数
thread: 要终止线程的ID
返回值: 成功返回0;失败返回错误码
3、线程等待(pthread_join阻塞式等待)
线程等待函数使用
功能: 等待线程结束(默认阻塞式等待)
原型int pthread_join(pthread_t thread, void **value_ptr);
参数
thread: 要等待的线程的ID
value_ptr: 它指向⼀个指针,后者指向线程的返回值,这个参数是为了看到新线程的返回值,因为线程的返回值是void*,因此我们传的时候要穿void**,也就是说这个参数是一个指向指针的指针。
返回值: 成功返回0;失败返回错误码
注意:线程在等待时只需要获取退出码就行,因为线程结束只有两种情况,代码跑完结果对和代码跑完结果不对,不会有异常退出的情况,因为一旦有一个线程出现了异常,整个进程都有可能会挂掉
调用该函数的线程将挂起等待,直到id为thread的线程终止(阻塞式等待)。 thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,总结如下:
- 如果thread线程通过return返回,value_ ptr所指向的单元里存放的是thread线程函数的返回值。
- 如果thread线程被别的线程调用pthread_ cancel异常终掉,value_ ptr所指向的单元里存放的是常数PTHREAD_CANCELED(值为-1)。
- 如果thread线程是自己调用pthread_exit终止的,value_ptr所指向的单元存放的是传给pthread_exit的参数。
- 如果对thread线程的终止状态不感兴趣,可以传NULL给value_ ptr参数
示例代码:
运行结果及分析:
4、线程分离(pthread_detach)
默认情况下,新创建的线程是joinable的,线程退出后,需要对其进行线程等待pthread_join操作,否则无法释放资源,从而造成系统泄漏。
如果不关心线程的返回值,join是一种负担,这个时候,我们可以告诉系统,当线程退出时,自动释放线程资源。
函数使用:
功能: 分离一个线程
int pthread_detach(pthread_t thread);
参数: thread表示要分离的线程id,也可以线程自己分离自己
返回值: 成功返回0;失败返回错误码
这里我们需要注意的是,一个线程如果被分离了,那么这个线程就不能被创建该线程的线程所等待。
验证代码:
操作结果: