1.什么是线程?
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的、能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(寄存器和栈),当时它与同属于一个进程的其他的线程共享进程所拥有的全部资源。
2.为什么有了进程还需要线程?
此时,我们要从进程的几个缺点入手进行思考。
(1)从资源上来讲:进程的创建需要大量的资源,而线程是一种非常“节俭”的多任务操作方式。
(2)从切换效率上来讲:因为每个进程相互独立,互不影响的特点,进程与进程之间的资源是不共享的。当频繁进行进程间的切换时,所带来的进程间上下文的切换的资源开销和时间开销是巨大的。而线程就弥补了这一点的不足,因为同一个进程间的多线程它们除了它们独立的寄存器和栈外是共享进程资源的,所以在进行线程切换时,它们所需要的线程间上下文切换的资源开销和时间开销是远远小于进程间切换的。
(3)从通信机制上来讲:还是同样的问题,因为不同进程间的资源互不共享,而要进行数据的传递只能通过进程间通信的方式进行,这种方式不仅费时,而且及其不方便。而线程则正因为它同一进程下的线程共享数据空间,所以一个线程的数据可以直接为其他线程所用,这不仅快捷,而且方便。
3.进程和线程的区别
线程事进程的一个执行单位,是进程内调度实体,比进程更小的独立运行的基本单位。(线程也被称为轻量级进程)
同一个进程的线程共享本进程的地址空间,而进程则是独立的地址空间。
一旦进程退出,则进程中所有的线程也全部退出。
一个进程崩溃后,不会对其他的进程产生影响,但是一个线程崩溃后,整个进程也会随之崩溃,所以说多进程比多线程更强壮。
线程不可能完全替代进程。
线程拥有的独立的属性:
每个线程都拥有自己独立的线程ID
每个线程都有独立的切换形态
调度的优先级
拥有自己独立的函数栈
拥有自己独立的错误号
每个线程都有自己独立的信号屏蔽字和未决信号机
每个线程有自己独立的tack_struct结构体
4.线程的特点
线程是不安全、不稳定、不健壮的(全局变量)
线程切换的开销很低(实质上就是函数的切换)
线程通信机制简单(全局变量)
5.线程操作
a)线程的创建
1)函数原型:
int pthread_create(pthread_t *thread,const pthread_attr_t *attr,void *(*start_routine)(void *),void *arg);
第一个参数:线程id(传出参数)
第二个参数:线程的属性(优先级、信号屏蔽字),一般为NULL
第三个参数:线程需要执行的函数(函数指针)
四字格参数:用来给线程函数传参(没有则为NULL)
2)头文件;
#include<pthread.h>
3)返回值:
成功:返回0
失败:返回非零错误号
b)线程的退出
1)被动退出:
a)函数原型:
int pthread_cancel(pthread_t thread);
参数:要退出线程的ID
b)头文件:
#include<pthread.h>
c)返回值:
成功:返回0
失败:返回非零错误号
2)主动退出:
a)函数原型:
void pthread_exit(void *retval);
参数:线程结束时的返回值
当返回值较多时,就封装成结构体,并返回结构体变量地址
b)头文件:
#include<pthread.h>
c)返回值:
成功:返回0
失败:返回非零错误号
3)注册线程退出处理函数:
a)函数原型:
void pthread_cleanup_push(void(*routine)(void*),void *arg);
(压栈)
参数1:将此函数注册为线程退出处理函数
参数2:传递给退出处理函数的参数
void pthread_cleanup_pop(int execute);
(弹栈)
参数1:若为!0:弹栈,并调用退出函数
若为0:不弹栈,并调用退出函数
b)头文件:
#include<pthread.h>
c)注意事项:
pthread_cleanup_push函数和pthread_cleanup_pop函数必须配对出现,若pthread_cleanup_pop函数调用不上也必须要写,否则编译不过
d)弹栈退出原则:
调用thread_cleanup_pop(!0);,主动弹栈
如果线程是被别人调用pthread_cancel取消,也会弹栈
如果线程是调用pthread_exit函数退出,也会弹栈
注:
return退出,不会自动弹栈,
如需弹栈,调用thread_cleanup_pop(!0);
c)线程等待
1)等待线程的目的
a)保证线程的退出程序:保证一个线程退出并且回收资源后允许下一个进程退出
b)回收线程退出时的资源情况:保证当前线程退出后,创建的新线程不会复用刚才退出线程的地址空间
c)获得新线程退出时的结果是否正确的退出:类似僵尸进程的wait,确保不会造成内存泄漏等问题
2)函数原型
函数原型:
int pthread_join(pthread_t thread, void **retval);
参数1:指定要回收次线程的TID
参数2:次线程函数返回的返回值
头文件:
#include<pthread.h>
返回值:
成功:返回0
失败:返回错误号
3)线程资源为什么不采用进程退出后一起回收?
有些程序(进程)一旦运行后将长期运行,不会结束,所以次线程在结束后,必须回收资源,如果不回收,每结束一个次线程就会导致一部分的资源被占用,慢慢积累就会使整个进程资源越来越少,最后导致进程崩溃,所以次线程结束后,必须回收次线程资源。
d)线程的状态
1)可结合态:
这种状态下的线程时能够被其他进程回收资源或者杀死的。
2)分离态:
这种状态下的线程是不能够被其他线程回收或杀死的。
它的存储资源在它终止时由系统自动释放
3)默认情况下,线程被创建成可结合态
4)如何避免多线程退出导致的内存泄漏?
每个可结合线程需要显示的调用pthread_join函数回收
将其变成分离态的线程:
线程分离函数:
pthread_detach(TID);
参数1:要分离线程的TID
修改属性:
pthread_attr_t
pthread_attr_init
pthread_attr_setdetachstate
(THREAD_CREATE_DETACHED)
pthread_attr_destroy
关于线程同步与互斥下一篇再更新。