什么是线程?
- 在一个程序里的一个执行路线就叫做线程(thread)。更准确的定义是:线程是“一个进程内部的控制序列”
- 一切进程至少都有一个执行线程
- 线程在进程内部运行
- 线程本质是在进程地址空间内运行
- linux没有真正的线程,是用进程模拟的
- 线程强调资源共享
- 线程是调度的基本单位
进程vs线程
-
进程是资源分配的基本单位
-
线程是调度的基本单位
-
每个线程的硬件都有自己的独立的上下文数据
-
线程共享进程数据,但也拥有自己的一部分数据
- 线程id
- 一组寄存器
- 栈
- errno
- 信号屏蔽字
- 调度优先级
进程的多个线程共享同一地址空间,如果定义一个函数,在各线程中都可以调用,如果定义一个全局变量,在各线程中都可以访问到,除此之外,哥线程还共享以下进程资源和环境:
- 文件描述符表
- 每种信号的处理方式(sig_ ign、sig_ dfl或者自定义的信号处理函数)
- 当前的工作目录
- 用户id和组id
让我们画一个进程与线程的关系图:
线程控制
posix线程库
- 与线程有关的函数构成一个完整的系列,绝大多数函数的名字都是以“pthread_”开头的
- 要使用这些线程库,要引入头文件
- 链接这些第三方库,编译器命令是“-lpthread”选项
1. 线程的创建
功能:创建一个新的线程
原型:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void*), void *arg);
参数:
thread:返回线程id
attr:设置线程的属性,attr为null表示使用默认属性
start_routine:是个函数地址,线程启动后要执行的函数
arg:传给线程启动函数的参数
返回值:成功返回0;失败返回错误码
错误检查:
- 传统的一些函数是,成功返回0,失败返回-1,并且对全局变量errno赋值以指示错误。
- pthreads函数出错时不会设置全局变量errno(而大部分其他posix函数会这样做)。而是将错误代码通过返 回值返回
- pthreads同样也提供了线程内的errno变量,以支持其它使用errno的代码。对于pthreads函数的错误,建议通 过返回值业判定,因为读取返回值要比读取线程内的errno变量的开销更小
让我们写一个代码来用一下这个线程:
#include
#include
#include
#include
#include
void *rout(void *arg)
{
int i;
for(; ;)
{
printf("i am thread 1\n");
sleep(1);
}
}
int main()
{
pthread_t tid;
int ret;
if((ret = pthread_create(&tid, null, rout, null) != 0))
{
fprintf(stderr, "pthresd_create: %s\n", strerror(ret));
exit(exit_failure);
}
int i;
for(;;)
{
printf("i am main thread");
sleep(1);
}
}
2. 线程终止
如果需要只终止某个线程而不终止整个进程,可以有三种方法:
- 从线程函数return。这种方法对主线程不适用,从main函数return相当于调用exit。
- 线程可以调用pthread_ exit终止自己
- 一个线程可以调用pthread_ cancel终止同一进程中的另一个线程
功能:线程终止
原型
void pthread_exit(void *value_ptr);
参数
value_ptr:value_ptr不要指向一个局部变量。
返回值:无返回值,跟进程一样,线程结束的时候无法返回到它的调用者(自身
3. 线程等待 为什么需要线程等待?
- 已经退出的线程,其空间没有被释放,仍然在进程的地址空间内
- 创建新的线程不会复用刚才线程退出的地址空间
功能:等待线程结束
原型
int pthread_join(pthread_t thread, void **value_ptr);
参数
thread:线程id
value_ptr:它指向一个指针,后者指向线程的返回值
返回值:
成功返回0;
失败返回错误码
调用该函数的线程将挂起等待,直到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参数。
4. 分离线程
- 默认情况下,新创建的线程是joinable的,线程退出后,需要对其进行pthread_join操作,否则无法释放资源,从而造成系统泄漏。
- 如果不关心线程的返回值,join是一种负担,这个时候,我们可以告诉系统,当线程退出时,自动释放线程的资源。
int pthread_detach(pthread_t thread);