本文探讨PODIX线程相关内容
线程的概念
什么是多线程,提出这个问题的时候,我还是很老实的拿出操作系统的书,按着上面的话敲下“为了减少进程切换和创建开销,提高执行效率和节省资源,我们引入了线程的概念,与进程相比较,线程是CPU调度的一个基本单位。”
当 Linux 最初开发时,在内核中并不能真正支持线程。那为什么要使用多线程?
使用多线程的理由之一是和进程相比,它是一种非常"节俭"的多任务操作方式。运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。
那么线程是干什么的呢?简要概括下线程的职责:线程是程序中完成一个独立任务的完整执行序列。
线程的管理
创建线程
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
- thread:线程id,唯一标识
- attr:线程属性,参数可选
- start_routine:线程执行函数
- arg:传递给线程的参数
Demo1:创建一个线程
#include <pthread.h>
#include <stdio.h>
void *workThreadEntry(void *args)
{
char*str = (char*)args;
printf("threadId:%lu,argv:%s\n",pthread_self(),str);
}
int main(int argc,char *agrv[])
{
pthread_t thread_id;
char*str = "hello world";
pthread_create(&thread_id,NULL,workThreadEntry,str);
printf("threadId=%lu\n",pthread_self());
pthread_join(thread_id,NULL);
}
编译运行
$ gcc -o main main.c -pthread
$ ./main
threadId=140381594486592
threadId:140381585938176,argv:hello world
运行结果是创建一个线程,打印线程id和主线程传递过来的参数。
线程退出与等待
在Demo1中我们用到了pthread_join
这个函数
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
这是一个阻塞函数,用于等待线程退出,对线程资源进行收回。
一个线程对应一个pthread_join()调用,对同一个线程进行多次pthread_join()调用属于逻辑错误,俗称耍流氓。
那么线程什么时候退出?
1.在线程函数运行完后,该线程也就退出了
2.线程内调用函数pthread_exit()
主动退出
3.当线程可以被取消时,通过其他线程调用pthread_cancel
的时候退出
4.创建线程的进程退出
5.主线程执行了exec类函数,该进程的所有的地址空间完全被新程序替换,子线程退出
线程的状态
线程pthread
有两种状态joinable
状态和unjoinable
状态,如果线程是joinable
状态,当线程函数自己返回退出时或pthread_exit
时都不会释放线程所占用堆栈和线程描述符(总计8K多)。只有当你调用了pthread_join
之后这些资源才会被释放。若是unjoinable
状态的线程,这些资源在线程函数退出时或pthread_exit
时自动会被释放。pthread
的状态在创建线程的时候指定,创建一个线程默认的状态是joinable
。
状态为joinable
的线程可在创建后,用pthread_detach()
显式地分离,但分离后不可以再合并,该操作不可逆。
#include <pthread.h>
int pthread_detach(pthread_t thread);
pthread_detach这个函数就是用来分离主线程和子线程,这样做的好处就是当子线程退出时系统会自动释放线程资源。
主线程与子线程分离,子线程结束后,资源自动回收。
线程取消
在线程的退出中我们说到线程可以被其他线程结束。
1.一个线程可以调用pthread_cancel
来取消另一个线程。
2.被取消的线程需要被join
来释放资源。
3.被取消的线程的返回值为PTHREAD_CANCELED
有关线程的取消,一个线程可以为如下三个状态:
1.可异步取消:一个线程可以在任何时刻被取消。
2.可同步取消:取消的请求被放在队列中,直到线程到达某个点,才被取消。
3.不可取消:取消的请求被忽略。
首先线程默认是可以取消的,通过pthread_setcancelstate
设置线程的取消状态属性
#include <pthread.h>
int pthread_setcancelstate(int state, int *oldstate);
int pthread_setcanceltype(int type, int *oldtype);
可取消 | 不可取消 |
---|---|
PTHREAD_CANCEL_ENABLE | PTHREAD_CANCEL_DISABLE |
调用pthread_setcanceltype来设定线程取消的方式:
pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); //异步取消、
pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL); //同步取消、
pthread_setcanceltype (PTHREAD_CANCEL_DISABLE, NULL); //不能取消
线程回收
Linux提供回收器(cleanup handler),它是一个API函数,在线程退出的时候被调用。
#include <pthread.h>
void pthread_cleanup_push(void (*routine)(void *),
void pthread_cleanup_